文章目录
Spring 中在使用注解(Annotation)会涉及到
< context:annotation-config>
和
< context:component-scan>
配置,下面就对这两个配置进行诠释。
1. @Autowired注解原理
1.1 @Autowired不生效演示
package com.test.springaop;
public class Car {
public Car() {
}
private String name ;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
Driver 有个属性,配置 @Autowired注解:
package com.test.springaop;
import org.springframework.beans.factory.annotation.Autowired;
public class Driver {
private String name;
@Autowired
private Car car;
public void setCar(Car car) {
this.car = car;
}
public void setName(String driver) {
this.name = driver;
}
public Car getCar() {
return this.car;
}
}
test-scan.xml,配置了driver和car的2个bean:
<?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.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<bean id="car" class="com.test.springaop.Car"/>
<bean id="driver" class="com.test.springaop.Driver"/>
</beans>
main方法执行类:
package com.test.springaop;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class MainClass {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("test-scan.xml");
//getBean的入参是代理bean,但是获得结果确实一个ISubject类型
Driver driver = ((Driver) context.getBean("driver"));
System.out.println(driver.getCar());
}
}
执行结果:
null
虽然我们期望driver的属性自动注入car,但是失败了,原因是spring目前识别不了 @Autowired注解
1.2 @Autowired生效演示
如何让注解生效?那么就必须事先在 Spring 容器中声明 AutowiredAnnotationBeanPostProcessor Bean,这是一个BeanPostProcessor后置处理器,专门用来解析带@Autowired注解的:
<bean class="org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor "/>
<bean id="car" class="com.test.springaop.Car"/>
<bean id="driver" class="com.test.springaop.Driver"/>
增加声明后,我们再来试下:
com.test.springaop.Car@1e397ed7
果然生效了,注入的car不为null了。
1.3 总结
要运用注解,需要注册相应的BeanPostProcessor后置处理器,因此汇总下:

-
@Autowired注解,那么就必须事先在 Spring 容器中声明 AutowiredAnnotationBeanPostProcessor Bean。传统声明方式如下
<bean class="org.springframework.beans.factory.annotation. AutowiredAnnotationBeanPostProcessor "/>
-
@ Resource 、@ PostConstruct、@ PreDestroy等注解就必须声明CommonAnnotationBeanPostProcessor。传统声明方式如下
<bean class="org.springframework.beans.factory.annotation. CommonAnnotationBeanPostProcessor"/>
-
@PersistenceContext注解,就必须声明PersistenceAnnotationBeanPostProcessor的Bean。
<bean class="org.springframework.beans.factory.annotation.PersistenceAnnotationBeanPostProcessor"/>
-
@Required的注解,就必须声明RequiredAnnotationBeanPostProcessor的Bean。
<bean class="org.springframework.beans.factory.annotation.RequiredAnnotationBeanPostProcessor"/>
2. context:annotation-config
一般来说,像@ Resource 、@ PostConstruct、@Antowired这些注解在自动注入还是比较常用,所以如果总是需要按照传统的方式一条一条配置显得有些繁琐和没有必要,于是spring给我们提供< context:annotation-config/>
的简化配置方式,自动帮你完成声明。
< context:annotation-config>
是用于激活那些已经在spring容器里注册过的bean上面的注解,也就是显示的向Spring注册如下四个后置处理器:
AutowiredAnnotationBeanPostProcessor
CommonAnnotationBeanPostProcessor
PersistenceAnnotationBeanPostProcessor
RequiredAnnotationBeanPostProcessor
现在读者可以自行修改test-scan.xml:
<context:annotation-config/>
<bean id="car" class="com.test.springaop.Car"/>
<bean id="driver" class="com.test.springaop.Driver"/>
执行结果也是ok的。
2.1 存在的不足
< context:annotation-config/>
可以帮助我们识别@Antowired注解,但是不能帮我我们识别@Component、@Controller、@Service等这些注解。
我们来验证下,修改test-scan.xml:
去掉注册的bean:
<context:annotation-config/>
<!--<bean id="car" class="com.test.springaop.Car"/>-->
<!--<bean id="driver" class="com.test.springaop.Driver"/>-->
我们修改Driver和Car,增加@Component:
import org.springframework.stereotype.Component;
@Component
public class Driver {
import org.springframework.stereotype.Component;
@Component
public class Car {
执行结果,报找不到driver这个bean,也就是说不识别@Component:
Exception in thread "main" org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'driver' available
此时,就需要用到context:component-scan了
3. context:component-scan
Spring 给我提供了context:component-scan配置,如下:
<context:component-scan base-package="XX.XX"/>
通过对base-package配置,就可以把指定路径下 @Component等注解全部扫描到context中!
该配置项其实也包含了自动注入上述processor的功能,因此当使用 < context:component-scan/> 后,就可以将 < context:annotation-config/> 移除了。
现在来试验下,修改test-scan.xml,增加scan标签:
<context:component-scan base-package="com.test.springaop"/>
<!--<context:annotation-config/>-->
<!--<bean id="car" class="com.test.springaop.Car"/>-->
<!--<bean id="driver" class="com.test.springaop.Driver"/>-->
执行是ok的:
com.test.springaop.Car@4cf4d528
4.总结
(1):<context:annotation-config />仅能够在已经在已经注册过的bean上面起作用。对于没有在spring容器中注册的bean,它并不能执行任何操作。
(2)context:component-scan除了具有<context:annotation-config />的功能之外,还具有自动将带有@component,@service,@Repository等注解的对象注册到spring容器中的功能。
4.1 如果同时使用这两个配置会不会出现重复注入的情况呢?
答案:不会重复注入,因为< context:annotation-config />和 < context:component-scan >同时存在的时候,前者会被忽略。如@autowire,@resource等注入注解只会被注入一次!
参考:
《Spring配置中context:annotation-config VS context:component-scan》