| |||||||||
| PREV CLASS NEXT CLASS | FRAMES NO FRAMES | ||||||||
| SUMMARY: INNER | FIELD | CONSTR | METHOD | DETAIL: FIELD | CONSTR | METHOD | ||||||||
Keyed-singleton implementation of BeanFactoryLocator, which leverages existing Spring constructs. This is normally accessed through LocatorFactory, but may also be used directly.
Please see the warning in BeanFactoryLocator's JavaDoc about appropriate usage of singleton style BeanFactoryLocator implementations. It is the opinion of the Spring team that the use of this class and similar classes is unecessary except (sometimes) for a small amount of glue code. Excessive usage will lead to code that is more tightly coupled, and harder to modify or test.
In this implementation, an ApplicationContext is built up from one or more XML definition files, accessed as resources. The default name of the resource file(s) is 'beanRefFactory.xml', which is used when the instance is obtained with the no-arg getInstance() method. Using getInstance(java.lang.String) will return a singleton instance which will use a name for the resource file(s) which is the specificed selector argument, instead of the default. The purpose of this Application Context is to create and hold a copy of one or more 'real' BeanFactory or Application Context instances, and allow those to be obtained either directly or via an alias. As such, it provides a level of indirection, and allows multiple pieces of code, which are not able to work in a Dependency Injection fashion, to refer to and use the same target BeanFactory/ApplicationContext instance(s), by different names.
Consider an example application scenario:
com.mycompany.myapp.util.applicationContext.xml - ApplicationContext
definition file which defines beans for 'util' layer.
com.mycompany.myapp.dataaccess-applicationContext.xml -
ApplicationContext definition file which defines beans for 'data access' layer.
Depends on the above
com.mycompany.myapp.services.applicationContext.xml -
ApplicationContext definition file which defines beans for 'services' layer.
Depends on the above
In an ideal scenario, these would be combined to create one ApplicationContext,
or created as three hierarchical ApplicationContexts, by one piece of code
somewhere at application startup (perhaps a Servlet filter), from which all other
code in the application would flow, obtained as beans from the context(s). However
when third party code enters into the picture, things can get problematic. If the
third party code needs to create user classes, which should normally be obtained
from a Spring BeanFactory/ApplicationContext, but can handle only newInstance()
style object creation, then some extra work is required to actually access and
use object from a BeanFactory/ApplicationContext. One solutions is to make the
class created by the third party code be just a stub or proxy, which gets the
real object from a BeanFactory/ApplicationContext, and delegates to it. However,
it is is not normally workable for the stub to create the BeanFactory on each
use, as depending on what is inside it, that can be an expensive operation.
Additionally, there is a fairly tight coupling between the stub and the name of
the definition resource for the BeanFactory/ApplicationContext. This is where
KeyedSingletonBeanFactoryLocator comes in. The stub can obtain a
KeyedSingletonBeanFactoryLocator instance, which is effectively a singleton, and
ask it for an appropriate BeanFactory. A subsequent invocation (assuming the
same classloader is involved) by the stub or another piece of code, will obtain
the same instance. The simple aliasing mechanism allows the context to be asked
for by a name which is appropriate for (or describes) the user. The deployer can
match alias names to actual context names.
Another use of KeyedSingletonBeanFactoryLocator, is to demand-load/use one or more
BeanFactories/ApplicationContexts. Because the definiiton can contain one of more
BeanFactories/ApplicationContexts, which can be independent or in a hierarchy, if
they are set to lazy-initialize, they will only be created when actually requested
for use.
Given the above=mentioned three ApplicationContexts, consider the simplest
KeyedSingletonBeanFactoryLocator usage scenario, where there is only one single
beanRefFactory.xml definition file:
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd"> <beans> <bean id="com.mycompany.myapp" class="org.springframework.context.support.ClassPathXmlApplicationContext"> <constructor-arg> <list> <value>com.mycompany.myapp.util.applicationContext.xml</value> <value>com.mycompany.myapp.dataaccess.applicationContext.xml</value> <value>com.mycompany.myapp.dataaccess.services.xml</value> </list> </constructor-arg> </bean> </beans>The client code is as simple as:
BeanFactoryLocator bfl = KeyedSingletonBeanFactoryLocator.getInstance();
BeanFactoryReference bf = bfl.useFactory("com.mycompany.myapp");
// now use some bean from factory
MyClass zed = bf.getFactory().getBean("mybean");
Another relatively simple variation of the beanRefFactory.xml definition file could be:
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd"> <beans> <bean id="com.mycompany.myapp.util" lazy-init="true" class="org.springframework.context.support.ClassPathXmlApplicationContext"> <constructor-arg> <value>com.mycompany.myapp.util.applicationContext.xml</value> </constructor-arg> </bean> <!-- child of above --> <bean id="com.mycompany.myapp.dataaccess" lazy-init="true" class="org.springframework.context.support.ClassPathXmlApplicationContext"> <constructor-arg> <value>com.mycompany.myapp.dataaccess.applicationContext.xml</value> </constructor-arg> <constructor-arg> <ref bean="com.mycompany.myapp.util"/> </constructor-arg> </bean> <!-- child of above --> <bean id="com.mycompany.myapp.services" lazy-init="true" class="org.springframework.context.support.ClassPathXmlApplicationContext"> <constructor-arg> <value>com.mycompany.myapp.dataaccess.services.xml</value> </constructor-arg> <constructor-arg> <ref bean="com.mycompany.myapp.dataaccess"/> </constructor-arg> </bean> <!-- define an alias --> <bean id="com.mycompany.myapp.mypackage" class="java.lang.String"> <constructor-arg> <value>com.mycompany.myapp.services</value> </constructor-arg> </bean> </beans>In this example, there is a hierarchy of three contexts created. The (potential) advantage is that if the lazy flag is set to true, a context will only be created if it's actually used. If there is some code that is only needed some of the time, this mechanism can save some resources. Additionally, an alias to the last context has been created. Aliases allow usage of the idiom where client code asks for a context with an id which represents the package or module the code is in, and the actual definition file(s) for the KeyedSingletonBeanFactoryLocator maps that id to a real context id.
beanRefFactory.xml for every module.
All the files are automatically combined to create the final definition.beanRefFactory.xml file inside jar for util module:<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd"> <beans> <bean id="com.mycompany.myapp.util" lazy-init="true" class="org.springframework.context.support.ClassPathXmlApplicationContext"> <constructor-arg> <value>com.mycompany.myapp.util.applicationContext.xml</value> </constructor-arg> </bean> </beans>
beanRefFactory.xml file inside jar for data-access module:<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd"> <beans> <!-- child of util --> <bean id="com.mycompany.myapp.dataaccess" lazy-init="true" class="org.springframework.context.support.ClassPathXmlApplicationContext"> <constructor-arg> <value>com.mycompany.myapp.dataaccess.applicationContext.xml</value> </constructor-arg> <constructor-arg> <ref bean="com.mycompany.myapp.util"/> </constructor-arg> </bean> </beans>
beanRefFactory.xml file inside jar for services module:<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd"> <beans> <!-- child of data-access --> <bean id="com.mycompany.myapp.services" lazy-init="true" class="org.springframework.context.support.ClassPathXmlApplicationContext"> <constructor-arg> <value>com.mycompany.myapp.dataaccess.services.xml</value> </constructor-arg> <constructor-arg> <ref bean="com.mycompany.myapp.dataaccess"/> </constructor-arg> </bean> </beans>
beanRefFactory.xml file inside jar for mypackage module. This doesn't
create any of its own contexts, but allows the other ones to be referred to be
a name known to this module:<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd"> <beans> <!-- define an alias --> <bean id="com.mycompany.myapp.mypackage" class="java.lang.String"> <constructor-arg> <value>com.mycompany.myapp.services</value> </constructor-arg> </bean> </beans>
| Field Summary | |
final static String | BEANS_REFS_XML_NAME |
| Method Summary | |
static BeanFactoryLocator | getInstance()Returns an instance which uses the default "beanRefFactory.xml", as the name of the definition file(s). |
static BeanFactoryLocator | getInstance(String selector)Returns an instance which uses the the specified selector, as the name of the definition file(s). |
BeanFactoryReference | useFactory(String factoryKey) |
| Field Detail |
public final static String BEANS_REFS_XML_NAME
| Method Detail |
public static BeanFactoryLocator getInstance()
throws org.springframework.beans.FatalBeanException
public static BeanFactoryLocator getInstance(String selector)
throws org.springframework.beans.FatalBeanException
public BeanFactoryReference useFactory(String factoryKey)
throws org.springframework.beans.FatalBeanException
| Association Links |
to Class java.util.Map
to Class java.util.Map
to Class java.util.Map
to Class java.lang.String
| |||||||||
| PREV CLASS NEXT CLASS | FRAMES NO FRAMES | ||||||||
| SUMMARY: INNER | FIELD | CONSTR | METHOD | DETAIL: FIELD | CONSTR | METHOD | ||||||||