其实前面我们已经在基于注解配置了,这是由于个人比较喜欢基于注解配置。
Spring官方文档提过一个问题:基于注解配置要好于基于xml的配置吗?其实各有千秋,根据个人喜好吧。重要的是Spring可以支持基于注解配置,也可以支持基于xml配置文件配置,也可以支持两者的混搭。
我们可以使用Spring的基于BeanPostProcessor的@Autowire注解,Spring也支持JSR-250的@PostConstruct和@PreDestroy注解,以及基于 JSR-330 (Dependency Injection for Java) 的注解 @Inject 和 @Named。
基于注解的依赖注入的执行要早于基于xml配置文件,所以如果同时使用的话,基于xml文件的配置要优先于基于注解的:xml配置会覆盖掉注解配置。
通过以下配置可以实现混合xml和注解的配置:
基于注解的配置的底层生效原理其实是通过BeanPostProcessor,配置项 context:annotation-config/在Spring容器中隐式的注册了如下BeanPostProcessor:
ConfigurationClassPostProcessor
AutowiredAnnotationBeanPostProcessor
CommonAnnotationBeanPostProcessor
PersistenceAnnotationBeanPostProcessor
EventListenerMethodProcessor
比如@Autoware注解就是通过AutowiredAnnotationBeanPostProcessor(postProcessProperties方法)生效的。
@Autowired注解可以作用在构造方法、属性、以及普通方法上,我们在前面的文章中已经做过说明。
作用在构造方法和普通方法上,会自动装配方法中的参数,作用在属性上则自动装配该属性。
@Autowired注解是通过类型匹配的,所以添加注解的参数类型和注册到Spring IoC容器中的Bean的类型必须要匹配,如果Spring IoC在自动装配的过程中找不到匹配的Bean执行注入的话,会发生注入失败,抛异常。
Spring可以支持将同一类型的Bean注入到集合对象中,比如:
public class MovieRecommender {
private Set movieCatalogs;
@Autowired
public void setMovieCatalogs(Set movieCatalogs) {
this.movieCatalogs = movieCatalogs;
}
// ...
}
则Spring IoC容器中的所有类型为MovieCatalog的Bean都会注入到movieCatalogs中。MovieCatalog可以通过实现 org.springframework.core.Ordered接口或者使用@Order注解、 @Priority注解实现排序。
也可以将同类型的对象注入到Map中:
public class MovieRecommender {
private Map movieCatalogs;
@Autowired
public void setMovieCatalogs(Map movieCatalogs) {
this.movieCatalogs = movieCatalogs;
}
// ...
}
此时Map的key值为bean name,value值为bean对象。
默认情况下@Autowired注解期望必须能够注入一个依赖对象到目标对象中,否则,如果没有匹配到、或者匹配到多个对象的话,注入失败,抛异常。
通过@Autowired对集合类型注入也要求必须要有至少一个bean存在,不存在的话会抛异常。
可以通过@Autowired的属性required来改变这一行为:默认情况下required = true,我们可以修改required = false,则允许匹配不到依赖对象的情况存在,此时不注入任何对象,目标对象的值为null。
当@Autowired作用于构造方法上的时候,required 设置为true的情况下,仅允许有一个构造方法设置为@Autowired。当多个构造方法被设置为@Autowired(required必须设置为false)的时候,Sping IoC在注入的时候会选择构造方法参数依赖注入满足程度最好的构造器执行注入。如果一个类有多个构造器、并且都没有设置@Autowired,则主构造器、或者默认的构造器会被执行;如果一个类只有一个构造器,那么该构造器就一定会被执行,即使该构造器并没有标注@Autowired。
java 8 的java.util.Optional、以及@Nullable(Spring5.0以后)同样可以用来标注@Autowired为非必须(等同于required=false):
public class SimpleMovieLister {
@Autowired
public void setMovieFinder(Optional movieFinder) {
...
}
}
最后:
The @Autowired, @Inject, @Value, and @Resource annotations are handled by Spring BeanPostProcessor implementations. This means that you cannot apply these annotations within your own BeanPostProcessor or BeanFactoryPostProcessor types (if any). These types must be ‘wired up’ explicitly by using XML or a Spring @Bean method.
由于@Autowired, @Inject, @Value, and @Resource是通过BeanPostProcessor实现的,所以如果你自己实现了一个BeanPostProcessor,那就不能用以上几个注解,用以上几个注解是无法实现BeanPostProcessor功能的(错过了BeanPostProcessor的时机)。
上一篇 Spring FrameWork从入门到NB -Lazy-initialized Beans