As we know, it's not allowed to pass properties variables in import tag in application context. So here I use a simple solution -- create a sub application context.
First, let's see what the parent application context looks like:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd">
<bean id="my.propertyPlaceholderConfigurer"
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations">
<list>
<value>classpath:/foo/my.properties</value>
</list>
</property>
</bean>
<import resource="classpath:META-INF/foo/bundle-service.xml"/>
<bean id="my.applicationContextLoader"
class="foo.config.ApplicationContextLoader"
init-method="initialize"
destroy-method="close">
<property name="propertyPlaceholder" ref="my.propertyPlaceholderConfigurer"/>
<property name="contextLocations">
<list>
<value>classpath:META-INF/foo/bundle-jms-${jms.server.type}.xml</value>
<value>classpath:META-INF/foo/bundle-jms-service.xml</value>
</list>
</property>
</bean>
</beans>
You can see that in my.applicationContextLoader I can use different kinds of JMS application contexts depending on the value of jms.server.type in properties. It could be hornetq or activemq. I guess you already understand how it works now.
So let's briefly see how ApplicationContextLoader implements:
public class ApplicationContextLoader implements ApplicationContextAware {
...
public void initialize() throws Exception {
loadedAppContext = new GenericApplicationContext(applicationContext);
XmlBeanDefinitionReader beanReader = null;
beanReader = new XmlBeanDefinitionReader(loadedAppContext);
/* only needed when those settings in spring jar are invisible, e.g. in OSGi platform
beanReader.setNamespaceHandlerResolver(new DefaultNamespaceHandlerResolver(
applicationContext.getClassLoader(), YOUR_HANDLER_MAPPINGS_LOCATION));
beanReader.setEntityResolver(new PluggableSchemaResolver(
applicationContext.getClassLoader(), YOUR_SCHEMA_MAPPINGS_LOCATION));
*/
for (Resource contextLocation : contextLocations) {
beanReader.loadBeanDefinitions(contextLocation);
}
if (propertyPlaceholder != null) {
propertyPlaceholder.postProcessBeanFactory(loadedAppContext.getBeanFactory());
}
loadedAppContext.refresh();
}
public void close() {
if (loadedAppContext != null) {
loadedAppContext.close();
}
}
}
That's it.
Note that remember that sub application context should avoid importing contexts in parent application context. This will cause beans being initialized twice even it's singleton.
2 comments:
Nice idea, thanks - can you can post the whole source for ApplicationContextLoader?
Nice idea but like transactions are not being propagated
Post a Comment