ICE09 . playing with java, scala, groovy and spring .

Playing with Spring

Spring Quicktip: Selecting beans during runtime

Posted by ice09 on February 13, 2010

Sometimes you want to select an actual bean implementation during runtime depending on the availability of other beans.

Example

You have a bean accessor which accesses some external component and is used in several beans all over your application in several application contexts.
Now lets assume you want to change the actual implementation of the accessor bean depending on the availability of some other bean extended-accessor, which might or might not be present during runtime. This selection should be transparent to the existing components, ie. if the bean extended-accessor is not available in the application context, the fallback is using accessor instead.

Implementation

There might be different solutions to this problem, to me the best one is using the magical BeanFactoryPostProcessor.

import org.springframework.beans.BeansException;
import org.springframework.beans.MutablePropertyValues;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;

public class AccessorBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
	
	protected String extendedTemplate;
	protected String accessorTemplate;
	protected String accessorTemplateFactory;
	
	public void setExtendedTemplate(String extendedTemplate) {
		this.extendedTemplate = extendedTemplate;
	}

	public void setAccessorTemplate(String accessorTemplate) {
		this.accessorTemplate = accessorTemplate;
	}

	public void setAccessorTemplateFactory(String accessorTemplateFactory) {
		this.accessorTemplateFactory = accessorTemplateFactory;
	}
	
	public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
		BeanDefinition beanDefinition = beanFactory.getBeanDefinition(accessorTemplateFactory);
		MutablePropertyValues pvalues = beanDefinition.getPropertyValues();
		Template accessorClass = (Template) (beanFactory.containsBean(extendedTemplate) ? beanFactory.getBean(extendedTemplate) : (Template) beanFactory.getBean(accessorTemplate));   

                //Set the property (the selected bean implementation) now during runtime
		pvalues.addPropertyValue("accessorTemplate", accessorClass);
	}

Now, this bean must be instantiated – it will be passed the bean definition of all beans in the application context. It retrieves the factory bean first, which itself will be dynamically instantiated with the extendedTemplate if it exists and accessorTemplate otherwise.
Together with a factory bean, this looks like this:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">

        <!-- Here the external definition can be imported (if it is, and the 
               bean extendedTemplate is defined, it will be passed to the factory bean) -->
	<import resource="classpath*:/extension.xml"/>
	
        <!-- Here the actual BeanFactoryPostProcessor is defined, the properties are 
               the Strings which identify the several beans -->
	<bean class="AccessorBeanFactoryPostProcessor">
		<property name="accessorTemplateFactory" value="accessorTemplateFactory"/>
		<property name="extendedTemplate" value="extendedTemplate"/>
		<property name="accessorTemplate" value="accessorTemplate"/>
	</bean>

        <!-- This is the actual bean which is used the the dependent beans - it is created 	
               by the factory bean, which is itself configured by BeanFactoryPostProcessor -->
        <bean id="actualTemplate" factory-bean="accessorTemplateFactory" factory-method="createAccessorTemplate" />

        <!-- This is the actual factory, which itself gets configured by the BeanFactoryPostProcessor -->
	<bean id="accessorTemplateFactory" class="AccessorTemplateFactory">
		<!-- will be modified during runtime -->
	</bean>

	<!-- This is the original accessor template bean, which is selected 
               if the extended bean is not present -->
        <bean id="accessorTemplate" class="AccessorTemplate" />

</beans>

Of course, the beans must implement the same interface. The included extension.xml is quite simple:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">

	<bean id="extendedTemplate" class="ExtendedTemplate" />

</beans>

Finally, the factory bean is simple as well, it is used to have a single point of creation – the property accessorBean is set by the BeanFactoryPostProcessor during runtime:

public class AccessorTemplateFactory {

	public Template bean;

	public void setAccessorTemplate(Template arg0) {
		this.bean = arg0;
	}

	public Template createAccessorTemplate() {
		return bean;
	}

}
Advertisements

2 Responses to “Spring Quicktip: Selecting beans during runtime”

  1. nagesh said

    I read this article, not sure whether my problem is relevant to this. I am using an existing service which has its own implementation of loading the datasource and user properties from the application context. Calling application needs to pass these properties and shouldn’t use the existing one. I have a control on the application context, but not on the (datasource) bean which is used for the db connection. This datasource bean is a common for many interfaces. So I shouldn’t change this. I am looking to change the properties of this datasource bean during run time. either to override the properties. I tried the placeholder option, but that has a security implications writing the user credentials to a property file. so leaving this to a last option, I want to change the properties of this datasource bean during runtime and make it work through the existing implementation(getconnection etc). can you please help?

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

 
%d bloggers like this: