从一个异常探索autowired 的原理。
首先环境是这样的:
public class Boss { @Autowired private Car car; } //@Component 加上这个注释,上面的Boss 的Autowired car就会失败,出现下面的异常 public class Car { private String brand; private double price; }
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" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd" > <context:component-scan base-package="com.baobaotao"></context:component-scan> <!-- 该 BeanPostProcessor 将自动起作用,对标注 @Autowired 的 Bean 进行自动注入 --> <bean class="org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor"/> <!-- 移除 boss Bean 的属性注入配置的信息 --> <bean id="boss" class="com.baobaotao.Boss"/> <!-- <bean id="office" class="com.baobaotao.Office"> <property name="officeNo" value="001"/> </bean> <bean id="car" class="com.baobaotao.Car" scope="singleton"> <property name="brand" value=" 红旗 CA72"/> <property name="price" value="2000"/> </bean>--> </beans>
测试类:
import com.baobaotao.Boss; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.AbstractJUnit4SpringContextTests; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(locations = {"classpath:/beans.xml"}) public class AutowiredlTest extends AbstractJUnit4SpringContextTests { @Autowired Boss boss; @Test public void aaa() { System.out.println("boss = " + boss); } }
结果是出现异常:
D:softjavajdk1.7injava -Didea.launcher.port=7533 "-Didea.launcher.bin.path=D:Program Files (x86)JetBrainsIntelliJ IDEA Community Edition 2016.1.2in" -Dfile.encoding=UTF-8 -classpath "D:softjavajdk1.7jrelibcharsets.jar;D:softjavajdk1.7jrelibdeploy.jar;D:softjavajdk1.7jrelibextaccess-bridge-64.jar;D:softjavajdk1.7jrelibextdnsns.jar;D:softjavajdk1.7jrelibextjaccess.jar;D:softjavajdk1.7jrelibextlocaledata.jar;D:softjavajdk1.7jrelibextsunec.jar;D:softjavajdk1.7jrelibextsunjce_provider.jar;D:softjavajdk1.7jrelibextsunmscapi.jar;D:softjavajdk1.7jrelibextzipfs.jar;D:softjavajdk1.7jrelibjavaws.jar;D:softjavajdk1.7jrelibjce.jar;D:softjavajdk1.7jrelibjfr.jar;D:softjavajdk1.7jrelibjfxrt.jar;D:softjavajdk1.7jrelibjsse.jar;D:softjavajdk1.7jrelibmanagement-agent.jar;D:softjavajdk1.7jrelibplugin.jar;D:softjavajdk1.7jrelib esources.jar;D:softjavajdk1.7jrelib t.jar;D:codewsspringhzspring-learn arget est-classes;D:codewsspringhzspring-learn argetclasses;C:Userslkms.m2 epositoryjunitjunit4.12junit-4.12.jar;C:Userslkms.m2 epositoryorghamcresthamcrest-core1.3hamcrest-core-1.3.jar;C:Userslkms.m2 epositoryorgspringframeworkspring-context4.3.5.RELEASEspring-context-4.3.5.RELEASE.jar;C:Userslkms.m2 epositoryorgspringframeworkspring-aop4.3.5.RELEASEspring-aop-4.3.5.RELEASE.jar;C:Userslkms.m2 epositoryorgspringframeworkspring-beans4.3.5.RELEASEspring-beans-4.3.5.RELEASE.jar;C:Userslkms.m2 epositoryorgspringframeworkspring-core4.3.5.RELEASEspring-core-4.3.5.RELEASE.jar;C:Userslkms.m2 epositorycommons-loggingcommons-logging1.2commons-logging-1.2.jar;C:Userslkms.m2 epositoryorgspringframeworkspring-expression4.3.5.RELEASEspring-expression-4.3.5.RELEASE.jar;C:Userslkms.m2 epositoryorgspringframeworkspring-web4.3.5.RELEASEspring-web-4.3.5.RELEASE.jar;C:Userslkms.m2 epositoryorgspringframeworkspring-test4.3.5.RELEASEspring-test-4.3.5.RELEASE.jar;D:Program Files (x86)JetBrainsIntelliJ IDEA Community Edition 2016.1.2libidea_rt.jar" com.intellij.rt.execution.application.AppMain AnnoIoCTest 十一月 11, 2017 2:21:34 下午 org.springframework.context.support.ClassPathXmlApplicationContext prepareRefresh INFO: Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@7a277bd2: startup date [Sat Nov 11 14:21:34 CST 2017]; root of context hierarchy 十一月 11, 2017 2:21:34 下午 org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions INFO: Loading XML bean definitions from class path resource [beans.xml] 十一月 11, 2017 2:21:35 下午 org.springframework.context.support.ClassPathXmlApplicationContext refresh WARNING: Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'boss': Unsatisfied dependency expressed through field 'car'; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'com.baobaotao.Car' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)} Exception in thread "main" org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'boss': Unsatisfied dependency expressed through field 'car'; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'com.baobaotao.Car' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)} at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:588) at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:88) at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:366) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1225) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:552) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:483) at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:306) at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230) at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:302) at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:197) at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:759) at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:866) at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:542) at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:139) at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:93) at AnnoIoCTest.main(AnnoIoCTest.java:8) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:601) at com.intellij.rt.execution.application.AppMain.main(AppMain.java:144) Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'com.baobaotao.Car' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)} at org.springframework.beans.factory.support.DefaultListableBeanFactory.raiseNoMatchingBeanFound(DefaultListableBeanFactory.java:1474) at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1102) at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1064) at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:585) ... 20 more Process finished with exit code 1
spring 的启动过程中会读取配置的xml,注册所有的 beanDefinition,这个是准备过程。 准备完后是 beanfactory 的refresh ,这个时候会 进行注解的处理, 也就是 BeanPostProcessor。 这其中就包含了对 bean 中包含的各种注解的 解析, 比如 Autowired 注解等。 AutowiredAnnotationBeanPostProcessor 的 postProcessPropertyValues 是继承于InstantiationAwareBeanPostProcessor 。 是对它的实现。 如果我们仔细观察这个错误堆栈, 也许我们会从中发现很多很多的细节。
参考:
http://blog.csdn.net/mack415858775/article/details/47721909 写得非常详细,非常好!