标签:
一个Spring注入问题,首先看一个普通Spring Bean,
public class Foo { @Autowired Bar bar; public void doSomething(){ bar.doSomething(); } }
Spring配置一:
<bean id="bar" class="com.test.Bar"></bean> <bean id="foo" class="com.test.Foo"></bean>
单元测试:
@Test public void test_doSomthing(){ ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext-test.xml"); Foo foo = ctx.getBean(Foo.class); foo.doSomething(); }
执行上述测试方法,报错
java.lang.NullPointerException at com.test.Foo.doSomething(Foo.java:15) at com.test.FooTest.test_doSomthing(FooTest.java:13)
即foo bean中的bar并未注入。
Spring配置二:
<context:component-scan base-package="com.test"></context:component-scan>
当改成配置二后执行上述单元测试方法便能成功通过。经分析日志及查看源代码,发现使用配置二时供装载了6个bean,如下所示:
DEBUG org.springframework.beans.factory.support.AbstractBeanDefinitionReader.loadBeanDefinitions(AbstractBeanDefinitionReader.java:216) Loaded 6 bean definitions from location pattern [applicationContext-test.xml] DEBUG org.springframework.context.support.AbstractApplicationContext.obtainFreshBeanFactory(AbstractApplicationContext.java:530) Bean factory for org.springframework.context.support.ClassPathXmlApplicationContext@3c4e80d3: org.springframework.beans.factory.support.DefaultListableBeanFactory@14cc51c8: defining beans [bar,foo,org.springframework.context.annotation.internalConfigurationAnnotationProcessor,org.springframework.context.annotation.internalAutowiredAnnotationProcessor,org.springframework.context.annotation.internalRequiredAnnotationProcessor,org.springframework.context.annotation.internalCommonAnnotationProcessor]; root of factory hierarchy
而使用配置一时只有两个bean,如下所示:
DEBUG org.springframework.beans.factory.support.AbstractBeanDefinitionReader.loadBeanDefinitions(AbstractBeanDefinitionReader.java:216) Loaded 2 bean definitions from location pattern [applicationContext-test.xml] DEBUG org.springframework.context.support.AbstractApplicationContext.obtainFreshBeanFactory(AbstractApplicationContext.java:530) Bean factory for org.springframework.context.support.ClassPathXmlApplicationContext@45ebbb93: org.springframework.beans.factory.support.DefaultListableBeanFactory@18481697: defining beans [bar,foo]; root of factory hierarchy
配置二执行单元测试通过的原因似乎就在于多出的这几个bean。是不是只要有context:component-scan元素在自动就会有这几个bean的产生?验证此假设
在配置一中添加一个无实际意义的context:component-scan元素,如下所示:
<context:component-scan base-package="com.nonexist"></context:component-scan>
这时执行单元测试能通过,同配置二一样也会装载6个bean。那么这6个bean中到底哪个对注入bar到Foo中起了作用呢?
经过断点调试发现是AutowiredAnnotationBeanPostProcessor bean起了作用,见输出日志:
2015-04-25 20:23:09 DEBUG org.springframework.beans.factory.annotation.InjectionMetadata.<init>(InjectionMetadata.java:60) Found injected element on class [com.test.Foo]: AutowiredFieldElement for com.test.Bar com.test.Foo.bar 2015-04-25 20:23:09 DEBUG org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:85) Processing injected method of bean ‘foo‘: AutowiredFieldElement for com.test.Bar com.test.Foo.bar 2015-04-25 20:23:09 DEBUG org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:245) Returning cached instance of singleton bean ‘bar‘ 2015-04-25 20:23:09 DEBUG org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.registerDependentBeans(AutowiredAnnotationBeanPostProcessor.java:424) Autowiring by type from bean name ‘foo‘ to bean named ‘bar‘ 2015-04-25 20:23:09 DEBUG org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:458) Finished creating instance of bean ‘foo‘
那么直接在配置一种显式添加AutowiredAnnotationBeanPostProcessor bean呢?如下所示:
<bean id="bar" class="com.tcl.account.service.test.Bar"></bean> <bean id="foo" class="com.tcl.account.service.test.Foo"></bean> <bean id="autowiredAnnotationBeanPostProcessor" class="org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor"></bean>
测试会不会通过?会通过。见日志:
DEBUG org.springframework.beans.factory.support.AbstractBeanDefinitionReader.loadBeanDefinitions(AbstractBeanDefinitionReader.java:216) Loaded 3 bean definitions from location pattern [applicationContext-test.xml] DEBUG org.springframework.context.support.AbstractApplicationContext.obtainFreshBeanFactory(AbstractApplicationContext.java:530) Bean factory for org.springframework.context.support.ClassPathXmlApplicationContext@7767d3c1: org.springframework.beans.factory.support.DefaultListableBeanFactory@1924ed52: defining beans [bar,foo,autowiredAnnotationBeanPostProcessor]; root of factory hierarchy DEBUG org.springframework.beans.factory.annotation.InjectionMetadata.<init>(InjectionMetadata.java:60) Found injected element on class [com.test.Foo]: AutowiredFieldElement for com.test.Bar com.test.Foo.bar DEBUG org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:85) Processing injected method of bean ‘foo‘: AutowiredFieldElement for com.test.Bar com.test.Foo.bar DEBUG org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:245) Returning cached instance of singleton bean ‘bar‘ DEBUG org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.registerDependentBeans(AutowiredAnnotationBeanPostProcessor.java:424) Autowiring by type from bean name ‘foo‘ to bean named ‘bar‘ DEBUG org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:458) Finished creating instance of bean ‘foo‘
那么为什么在配置文件中添加了context: componet-scan元素后就会自动添加那另外4个bean呢?经过断点调试发现Spring隐式装载的4个bean是在如下方法中加载的:
Set<BeanDefinitionHolder> org.springframework.context.annotation.AnnotationConfigUtils.registerAnnotationConfigProcessors(BeanDefinitionRegistry registry, Object source)
其调用链如下所示:
标签:
原文地址:http://my.oschina.net/zhuguowei/blog/406382