Spring Pitfalls

Spring is the most common used IOC container. Due to the many functionalities there are many source of errors not visible at first sight. A typical problem is a dependency tending to an incorrect created bean instance.

Postprocessors

Spring has the feature of allowing beans of the context to manipulate other beans, the bean factory or the bean definitions. To do so, Spring needs to create bean instances of these processor beans, Depending on the processor type (BeanPostProcessor, BeanFactoryPostProcessor, BeanDefinitionRegistryPostProcessor) this will be at an early point of lifecicle. This may result in the following problems:

* The bean need processing but has not been processed (like @Autowire annotation)
* The bean has a dependency which also need to be created and neither processed

Unfortunately these effects occur unexpected in most cases. The spring context of a complex application typically contains some postprocessors, some of spring itself, some from libraries like CXF. These processors often instantiate partial bean trees in advance without causing any trouble. But adding a new dependency at any position of this tree may result in a problem without any indication of the reason.

Searching Beans

If you search for beans of a type from a ListableBeanFactory the type is determined by the class attribute of the definition except for factory beans. The effective bean type can be determined by a method call only. To do so the factory bean has to be instantiated.

If this type check is done by a post processor you will run in the same problems as above.

Effects

These early instantiated beans are not completly initialized. This may occur to hole trees of beans. The effects are:

* NullPointerException due to a missing dependency not set by @Autowire
* access to a database without transaction or session due to no @Transactional proxy

Depending on the processing skipped these problems may occur on context startup or later when the bean is accessed.

Solutions

Some problems originated by missing post processing may be solved by implementing Ordered. But to determine the correct value to run the processors in the right order may need some experimental tries.

This will not help if you have dependent beans instantiated early by a FactoryBean. To avoid this instantiation you need to decouple tees dependencies. A special FactoryBean creating a Proxy may do the job. This bean must not have any dependency to the bean to decouple and need to offer the target bean type without instantiating the target bean (a simple property in the following solution):

public class DecouplingFactoryBean
implements FactoryBean, BeanFactoryAware, BeanClassLoaderAware, InvocationHandler
{
private String beanName;
private Class objectType;
private BeanFactory beanFactory;
private ClassLoader classLoader;

@Override
@SuppressWarnings("unchecked")
public T getObject() {
return (T) Proxy.newProxyInstance(classLoader, new Class[] {objectType}, this);
}

@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
T bean = (beanName == null) ? beanFactory.getBean(objectType) : beanFactory.getBean(beanName, objectType);
return method.invoke(bean, args);
}

@Override
public Class getObjectType()
{
return objectType;
}

@Override
public boolean isSingleton() {
return true;
}

public void setBeanName(String name)
{
this.beanName = name;
}

@Required
public void setObjectType(Class type)
{
this.objectType = type;
}

@Override
public void setBeanFactory(BeanFactory beanFactory) {
this.beanFactory = beanFactory;
}

@Override
public void setBeanClassLoader(ClassLoader classLoader) {
this.classLoader = classLoader;
}
}


This DecouplingFactoryBean may be added between the factory bean and the dependency not to be instantiated to avoid a direct dependency. Using the proxy and getting the target in the invocation handler in a lazy manner solves the problem.

<bean id="earlyBean" class="...">
<property name="lateDependency" ref="lateBean"/>
</bean>

<bean id="lateBean" class="my.late.Bean"/>


becomes

<bean id="earlyBean" class="...">
<property name="lateDependency">
<bean class="diergo.util.spring.DecouplingFactoryBean">
<property name="beanName" value="lateBean"/>
<property name="objectType" value="my.late.BeanTypeOrInterface"/>
</bean>
</property>
</bean>

<bean id="lateBean" class="my.late.Bean"/>


The advantage of this solution is the lack of changing any existing bean or test code.

The problem will remain if the dependency will be used on initialization of the bean like at afterPropertiesSet(). In this case the DecouplingFactoryBean is useless. In this case try to change the bean code to use lazy init instead.