Saturday, October 6, 2012

Spring Autowire - Subtle behavior difference in xml and @Configuration

There is a subtle difference in the behavior of how autowire behaves with new @Configuration style of Spring bean configuration and using an xml file:

Consider a service into which a Dao is wired in:

public class SampleService {
 @Autowired private SampleDao sampleDao;
 
 public Sample getSample(int id){
  return this.sampleDao.findOne(id);
 }
}

Using an xml, the bean configuration would have been defined this way:

<bean name="sampleDao" class="SampleDaoImpl"/>
 <bean name="sampleService" class="SampleService"/>

and using the new @Configuration style it is defined this way:

@Configuration
public class AnnotationConfig {
 @Bean
 public SampleDao sampleDao(){
  return new SampleDaoImpl();
 }
 
 @Bean
 public SampleService sampleService(){
  return new SampleService();
 }
}

Now consider a program which uses the @Configuration defined bean configuration:

public static void main(String[] args) {
  ApplicationContext ctx = new AnnotationConfigApplicationContext(AnnotationConfig.class);
  SampleService sampleService = ctx.getBean(SampleService.class);
  System.out.println(sampleService.getSample(10));
 }

and a similar one using xml bean configuration:
public static void main(String[] args) {
  ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("springconfig.xml");
  SampleService sampleService = ctx.getBean(SampleService.class);
  System.out.println(sampleService.getSample(10));
 }

The behavior is that the SampleDao will not get correctly autowired into the SampleService in the case of xml based bean configuration but works correctly for @Configuration based bean configuration.

The reason for the behavior difference is that in the @Configuration case the AutowiredAnnotationBeanPostProcessor responsible for autowiring the fields is registered automatically whereas with XML bean configuration it has to be done explicitly. So the fix is to include AutowiredAnnotationBeanPostProcessor, which can be done in a few different ways, one of which is using:

<context:annotation-config/>

Note: I have deliberately demonstrated this in a main method instead of a unit test - In a unit test with Spring test support, the AutowiredAnnotationBeanPostProcessor is automatically registered by the test context and this behavior difference will not be seen there.

1 comment: