
Large scale development environments are typically composed of multiple application component stacks each of which can be represented as a directed graph of dependencies between components.

For each application there is typically a single top node (the web or desktop application layer). From this node the dependencies spread out to the various components which the application requires. Further down the stack these dependencies join where low level components are shared by higher level components for re-usability.
When you decide to go full stack Spring, modularity can get tricky, the Spring documentation typically tells you to bootstrap the application context in code or via the deployment descriptor (web.xml for j2ee web applications using ContextLoaderListener).
In code this is done by instantiating one of the ApplicationContext variants:
ApplicationContext context = new ClassPathXmlApplicationContext(new String[] {"a1-file.xml", "a2-file.xml"});
In the web.xml the configuration is quite similar:
<context-param> <param-name>contextConfigLocation</param-name> <param-value>/WEB-INF/a1-file.xml /WEB-INF/a2-file.xml</param-value> </context-param> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener>
But now what happens when you want to inject dependencies from lower level components into higher level components? The most straightforward solution is to add an import into A‘ s context file:
<beans>
<import resource="classpath*:b1-file.xml"/>
<import resource="classpath*:b2-file.xml"/>
<import resource="classpath*:c1-file.xml"/>
<import resource="classpath*:c2-file.xml"/>
<!-- from here on A's beans can be injected with b's and c's beans -->
</beans>
This seems easy but has some obvious pitfalls. For starters we just stated that A has to manage the bean definition for the entire stack which reeks of a maintenance hurdle. A more natural approach would be to have each component manage its own bean definition and define a single dependency between each component in the graph.
To solve this we can create a single file in each component, a descriptor file if you wish, and import only that component’s file-set in the descriptor file.
So B‘s and C‘s descriptors would look like
SpringDescriptor.xml in component B:
<beans>
<import resource="classpath*:b1-file.xml"/>
<import resource="classpath*:b2-file.xml"/>
</beans>
SpringDescriptor.xml in component C:
<beans>
<import resource="classpath*:c1-file.xml"/>
<import resource="classpath*:c2-file.xml"/>
</beans>
This way we can define a single import for all the components in our stack in A‘s context:
<beans>
<import resource="classpath*:**/**SpringDescriptor*.xml"/>
<!-- from here on A's beans can be injected with any component that contains the SpringDescriptor*.xml files -->
</beans>
So is this good enough? IMO no, it still has some drawbacks. When you load your beans this way, everything gets piled loaded into a single ApplicationContext which is created at the application’s entry point and contains beans from the entire stack. For small applications with few dependencies this might work but when this scales up things might get tangled. For example defining BeanPostProcessor or PropertyPlaceholderConfigurer for a single-component-scope is not possible in this design and is often desirable.
Another evil scenario I’ve come across is one where due to improper initialization of the application context (using a static singleton for bootstrapping application context) the application context actually gets initialized twice. Spring references this scenario in Glue code and the evil singleton.
To the rescue comes ContextSingletonBeanFactoryLocator which brings a bombastrous name and a handy solution for the task at hand.
The idea here is that every component contains a descriptor XML file (similar to our SpringDescriptor.xml, the default convention is beanRefContext.xml which can be customized by defining a different selector). This descriptor is keyed and defines the application context for that component.
Here is an example of the beanRefContext.xml from our B component.
<beans>
<bean id="bContext"
class="org.springframework.context.support.ClassPathXmlApplicationContext">
<constructor-arg>
<list>
<value>b1-file.xml</value>
<value>b2-file.xml</value>
</list>
</constructor-arg>
<constructor-arg ref="cContext">
</bean>
</beans>
As you can see this is nothing short of instantiating an ApplicationContext for each component in our graph, taking advantage of the second constructor argument of ClassPathXmlApplicationContext which defines a parent context. Yes, ApplicationContexts can be chained in a hierarchy (unidirectional, beans can “see” other beans in parent contexts only and not vice-versa).
Bootstrapping the context in code is the carried out this way:
BeanFactoryLocator beanFactoryLocator = ContextSingletonBeanFactoryLocator.getInstance();
BeanFactoryReference beanFactoryReference = beanFactoryLocator.useBeanFactory("aContext");
BeanFactory beanFactory = beanFactoryReference.getFactory();
Note that the getInstance method of the ContextSingletonBeanFactoryLocator class has an overload which accepts a selector argument designating the convention for descriptor files.
In a web deployment the ContextSingletonBeanFactoryLocator is utilized using the LOCATOR_FACTORY_KEY_PARAM and the LOCATOR_FACTORY_SELECTOR_PARAM of the ContextLoader class. These can be specified in web.xml
<context-param> <param-name>parentContextKey</param-name> <param-value>aContext</param-value> </context-param> <!-- Specfies the parent context of the root WebApplicationContext --> <context-param> <param-name>locatorFactorySelector</param-name> <param-value>SpringDescriptor.xml</param-value> </context-param> <!-- Specifies a different convention. the default being beanRefContext.xml -->
The only problem which remains is how to define components with more than one parent contexts. This cannot be done with the standard ApplicationContext as it only accepts a single context for the parent, which forces a liner hierarchy between contexts. You could still arrange the context so that all beans have the desired visibility scope for example the dependency graph shown above could be organized the following way:

Finally, with the introduction of Spring OSGi the approach towards initialization and life-cycle of ApplicationContexts has changed but more on that in another post.
No Trackbacks
You can leave a trackback using this URL: http://techo-ecco.com/blog/spring-application-context-hierarchy-and-contextsingletonbeanfactorylocator/trackback/
5 Comments
Thanks. I’ve been using the “straightforward” import method and have been uneasy about it the whole time though I couldn’t pinpoint why (the import method has done well for us so far but probably because our webapp is small right now) . Your post gives me some things to think about and redesign before we grow the webapp and get stuck in an import dilemma.
I’ve tried this technique with success, with the parent being an “EJB” (jar) and child being a war. Where I got stuck however is when it came to the need for the resource-ref’ed datasource defined in the war being usable by the EJB.
Unusable? meaning you cannot access it? a common way of dealing with data sources is to retrieve the via JNDI
This is brilliant idea, but doesot work for scenario below.
So you load the PropertyPlaceholderConfigurer context xml at the parentRootContext.
These properties are not available to the application context that are not part of the parentRootContext, in case of multiple context roots.
PropertyPlaceholderConfigurer only works for a single applicationContext layer, this could be useful for some scenarios and unuseful for others.