从一个异常探索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:\soft\java\jdk1.7\bin\java -Didea.launcher.port=7533 "-Didea.launcher.bin.path=D:\Program Files (x86)\JetBrains\IntelliJ IDEA Community Edition 2016.1.2\bin" -Dfile.encoding=UTF-8 -classpath "D:\soft\java\jdk1.7\jre\lib\charsets.jar;D:\soft\java\jdk1.7\jre\lib\deploy.jar;D:\soft\java\jdk1.7\jre\lib\ext\access-bridge-64.jar;D:\soft\java\jdk1.7\jre\lib\ext\dnsns.jar;D:\soft\java\jdk1.7\jre\lib\ext\jaccess.jar;D:\soft\java\jdk1.7\jre\lib\ext\localedata.jar;D:\soft\java\jdk1.7\jre\lib\ext\sunec.jar;D:\soft\java\jdk1.7\jre\lib\ext\sunjce_provider.jar;D:\soft\java\jdk1.7\jre\lib\ext\sunmscapi.jar;D:\soft\java\jdk1.7\jre\lib\ext\zipfs.jar;D:\soft\java\jdk1.7\jre\lib\javaws.jar;D:\soft\java\jdk1.7\jre\lib\jce.jar;D:\soft\java\jdk1.7\jre\lib\jfr.jar;D:\soft\java\jdk1.7\jre\lib\jfxrt.jar;D:\soft\java\jdk1.7\jre\lib\jsse.jar;D:\soft\java\jdk1.7\jre\lib\management-agent.jar;D:\soft\java\jdk1.7\jre\lib\plugin.jar;D:\soft\java\jdk1.7\jre\lib\resources.jar;D:\soft\java\jdk1.7\jre\lib\rt.jar;D:\code\ws\spring\hz\spring-learn\target\test-classes;D:\code\ws\spring\hz\spring-learn\target\classes;C:\Users\lkms\.m2\repository\junit\junit\4.12\junit-4.12.jar;C:\Users\lkms\.m2\repository\org\hamcrest\hamcrest-core\1.3\hamcrest-core-1.3.jar;C:\Users\lkms\.m2\repository\org\springframework\spring-context\4.3.5.RELEASE\spring-context-4.3.5.RELEASE.jar;C:\Users\lkms\.m2\repository\org\springframework\spring-aop\4.3.5.RELEASE\spring-aop-4.3.5.RELEASE.jar;C:\Users\lkms\.m2\repository\org\springframework\spring-beans\4.3.5.RELEASE\spring-beans-4.3.5.RELEASE.jar;C:\Users\lkms\.m2\repository\org\springframework\spring-core\4.3.5.RELEASE\spring-core-4.3.5.RELEASE.jar;C:\Users\lkms\.m2\repository\commons-logging\commons-logging\1.2\commons-logging-1.2.jar;C:\Users\lkms\.m2\repository\org\springframework\spring-expression\4.3.5.RELEASE\spring-expression-4.3.5.RELEASE.jar;C:\Users\lkms\.m2\repository\org\springframework\spring-web\4.3.5.RELEASE\spring-web-4.3.5.RELEASE.jar;C:\Users\lkms\.m2\repository\org\springframework\spring-test\4.3.5.RELEASE\spring-test-4.3.5.RELEASE.jar;D:\Program Files (x86)\JetBrains\IntelliJ IDEA Community Edition 2016.1.2\lib\idea_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 写得非常详细,非常好! |