And if so which configuration is needed? Is this not recommended?
The annotated class:
package com.springbug.beanfactorydependencyissue;
import javax.annotation.Resource;
import org.springframework.stereotype.Component;
@Component
public class DependantBean {
@Resource
DependencyBean dependencyBean; // Isn't initialized correctly
public DependencyBean getDependencyBean() {
return dependencyBean;
}
}
The dependency bean that fails:
package com.springbug.beanfactorydependencyissue;
import org.springframework.stereotype.Component;
@Component
public class DependencyBean {
}
Testcase:
package com.springbug.beanfactorydependencyissue;
import static org.fest.assertions.Assertions.assertThat;
import javax.annotation.Resource;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.testng.AbstractTestNGSpringContextTests;
import org.testng.annotations.Test;
import com.springbug.beanfactorydependencyissue.DependantBean;
@ContextConfiguration(locations = "/applicationContext.xml")
public class AppTest extends AbstractTestNGSpringContextTests {
@Resource
private DependantBean annotatedBean;
@Test
public void testThatDependencyIsInjected() {
// Fails as dependency injection of annotatedBean.dependencyBean does not work
assertThat(annotatedBean.getDependencyBean()).isNotNull();
}
}
A custom BeanFactoryPostProcessor with the "faulty" dependency:
package com.springbug.beanfactorydependencyissue;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class BeanFactoryPostProcessorConfiguration {
/**
* The {@link DependantBean} here causes the bug, can
* {@link BeanFactoryPostProcessor} have regular beans as dependencies?
*/
@Bean
public static BeanFactoryPostProcessor beanFactoryPostProcessor(
DependantBean dependantBean) {
return new BeanFactoryPostProcessor() {
public void postProcessBeanFactory(
ConfigurableListableBeanFactory beanFactory)
throws BeansException {
}
};
}
}
applicationContext.xml:
<?xml version="1.0" encoding="UTF-8"?>
<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">
<context:component-scan base-package="com.springbug.beanfactorydependencyissue" />
</beans>
Why can't BeanFactoryPostProcessorConfiguration
reference DependantBean
?
The resulting DependantBean
instance in AppTest
is not null, i.e it's created by spring, but its dependencies (DependencyBean
) are null. The fact that Spring doesn't complain at all leads me to believe that this is a bug within spring. Should this use-case be supported or not?
Btw, I'm using spring-*-3.1.1.RELEASE.jar Btw 2: the code to reproduce the bug can also be found here.
Maybe more simpler and descriptive answer:
Yes, it is possible to use @Component
bean as BeanFactoryPostProcessor
dependency.
However every dependency of a BeanFactoryPostProcessor
will be instantiated before any BeanPostProcessor
is active. And these include:
CommonAnnotationBeanPostProcessor
- responsible for @PostConstruct
, @Resource
and some other annotationsAutowiredAnnotationBeanPostProcessor
- responsible for @Autowired
and @Value
annotationsSo tu sum it up:
Yes, it is possible to use @Component
bean as BeanFactoryPostProcessor
dependency, but they can not use annotation based injection (@Autowired
, @Resource
, @WebServiceRef
, ...) and other features provided by BeanPostProcessor
s .
Workaround for your example might be to create ApplicationContext
hierarchy as you have suggested:
Other approaches might be (which I would prefer):
BeanFactoryAware
interface on your @Component
bean and pull your dependency yourself (as Spring will not inject it).BeanFactoryPostProcessor
s within context configuration XML
or @Configuration
(i.e. don't use @Component
for these beans).