Spring中我们可以使用以下三个自动装配的注解进行依赖注入:
@Autowired注解默认是按照类型(byType)装配依赖对象,默认情况下它要求依赖对象必须存在,当没有找到相应bean的时候,IOC容器就会报错。不过@Autowired有个required属性,可以配置为false,如果配置为false之后,当没有找到相应bean的时候就注入null,系统不会抛错。如果我们想使用按照名称(byName)来装配,可以结合@Qualifier注解一起使用。
@Resource默认按照名字(byName)装配依赖对象,由JAVAEE提供,需要导入包javax.annotation.Resource。@Resource有两个重要的属性:name和type,而Spring将@Resource注解的name属性解析为bean的名字,而type属性则解析为bean的类型。所以,如果使用name属性,则使用byName的自动注入策略,而使用type属性时则使用byType自动注入策略。如果既不制定name也不制定type属性,这时将通过反射机制使用byName自动注入策略。
@Inject注解默认也是按照类型(byType)装配依赖对象,如果需要按名称进行装配,则需要配合@Named注解。@Inject 注解没有 required 属性,因此在找不到合适的依赖对象时 inject 会系统会报错失败。 使用 @Inject 需要添加如下依赖:
<dependency> <groupId>javax.inject</groupId> <artifactId>javax.inject</artifactId> <version>1</version> </dependency> 复制代码
在Spring框架内部实现当中,注解实现注入主要是通过bean后置处理器BeanPostPocessor接口的实现类来生效的。BeanPostProcessor后置处理器是在spring容器启动时,创建bean对象实例后,马上执行的,对bean对象实例进行加工处理。
@Autowired是通过BeanPostProcessor接口的实现类AutowiredAnnotationBeanPostProcessor来实现对bean对象对其他bean对象的依赖注入的;
@Resource和@Inject是通过BeanPostProcessor接口的实现类CommonAnnotationBeanPostProcessor来实现的,顾名思义即公共注解CommonAnotation,CommonAnnotationBeanPostProcessor是Spring中统一处理JDK中定义的注解的一个BeanPostProcessor。该类会处理的注解还包括@PostConstruct,@PreDestroy等。
AutowiredAnnotationBeanPostProcessor和CommonAnnotationBeanPostProcessor添加到Spring容器的BeanPostProcessor的条件,即激活这些处理器的条件如下:
在对应的Spring容器的配置xml文件中,如applicationContext.xml,添加<context:annotation-config />和<context:component-scan />,或者只使用<context:component-scan />。 两者的区别是:<context:annotation-config />只查找并激活已经存在的bean,如通过xml文件的bean标签生成加载到Spring容器的,而不会去扫描如@Controller等注解的bean,查找到之后进行注入;而<context:component-scan />除了具有<context:annotation-config />的功能之外,还会去加载通过basePackages属性指定的包下面的,默认为扫描@Controller,@Service,@Component,@Repository注解的类。不指定basePackages则是类路径下面,或者如果使用注解@ComponentScan方式,则是当前类所在包及其子包下面。
如果是基于配置类而不是基于applicationContext.xml来对Spring进行配置,如SpringBoot,则在内部使用的IOC容器实现为AnnotationConfigApplicationContext或者其派生类,在AnnotationConfigApplicationContext内部会自动创建和激活以上的BeanPostProcessor。 如果同时存在基于xml的配置和配置类的配置,而在注入时间方面,基于注解的注入先于基于XML的注入,所以基于XML的注入会覆盖基于注解的注入。