Autowired、Resource、Inject 这几个都是用来做依赖注入的,我们挨个的来看一下。
Autowired可以加在构造函数、方法、方法参数、成员变量、注解上,从Spring4.3开始,如果bean只有一个构造函数,或者只有一个primary/default的构造函数,那么构造函数上的Autowired可以不加,否则还是要在某个构造函数上明确的加上Autowired。
源码如下:
@Target({ElementType.CONSTRUCTOR, ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Autowired {
boolean required() default true;
}
举个例子:
public class MovieRecommender {
private final CustomerPreferenceDao customerPreferenceDao;
//成员变量注入
@Autowired
private MovieCatalog movieCatalog;
//构造函数注入,此处可以省略
@Autowired
public MovieRecommender(CustomerPreferenceDao customerPreferenceDao) {
this.customerPreferenceDao = customerPreferenceDao;
}
}
还可以注入到集合里面:
public class MovieRecommender {
//所有的MovieCatalog类型的bean
@Autowired
private MovieCatalog[] movieCatalogs;
}
}
当然也可以注入到map:
public class MovieRecommender {
//map的key是bean的名字,value是bean:
private Map<String, MovieCatalog> movieCatalogs;
@Autowired
public void setMovieCatalogs(Map<String, MovieCatalog> movieCatalogs) {
this.movieCatalogs = movieCatalogs;
}
}
默认Autowired是不允许为空的,如果允许为空可以设置Autowired(required = false):
public class SimpleMovieLister {
private MovieFinder movieFinder;
//此时,MovieFinder 这个bean可以不存在
@Autowired(required = false)
public void setMovieFinder(MovieFinder movieFinder) {
this.movieFinder = movieFinder;
}
}
此外还可使用java8里面提供的java.util.Optional:
public class SimpleMovieLister {
@Autowired
public void setMovieFinder(Optional<MovieFinder> movieFinder) {
}
}
在Spring5.0中还可以使用JSR305的javax.annotation.Nullable:
public class SimpleMovieLister {
@Autowired
public void setMovieFinder(@Nullable MovieFinder movieFinder) {
}
}
此外,可以用Autowired直接注入BeanFactory, ApplicationContext, Environment, ResourceLoader, ApplicationEventPublisher, and MessageSource,还有他们的扩展接口:ConfigurableApplicationContext、ResourcePatternResolver。
需要注意的是:Autowired, Inject, Value, 和 Resource 都是由Spring的BeanPostProcessor来处理的(其中Autowired和Value是由AutowiredAnnotationBeanPostProcessor来处理的),因此,在你自己定义的BeanPostProcessor或者BeanFactoryPostProcessor里面是不可以使用这些注解的,要么使用xml要么使用Bean。
那么构造函数注入与setter方法注入该如何选择呢?
一般来说,如果不能为空必须要注入的,使用构造函数注入,允许为空可以不注入的则可以选择setter方法注入。
当多个候选bean都满足注入条件的时候,Primary标记的bean的优先级更高,比如:
@Configuration
public class DemoApp {
@Bean
public IService service1(){
return new Service1();
}
@Bean
public IService service2(){
return new Service2();
}
@Bean
public Service3 service3(IService iService){
return new Service3(iService);
}
}
Service3在注入IService的时候就会报错,因为容器中有2个IService:
Caused by: org.springframework.beans.factory.NoUniqueBeanDefinitionException:
No qualifying bean of type 'com.github.xjs.iocdemo.injectanno.IService' available:
expected single matching bean but found 2: service1,service2
可以在service1()或者service2()任意一个上添加Primary得以解决,如下:
@Bean
@Primary
public IService service2(){
return new Service2();
}
可以用一个标识符在多个候选的bean中选择注入的bean,默认的标识符是bean的名字。
因此前一个例子也可以这样来解决:
public Service3 service3(@Qualifier("service2") IService iService){
return new Service3(iService);
}
需要说明的是,Qualifier标识符不需要全局唯一,因为Autowired主要还是按照类型来进行注入的,如果多个Qualifier都满足,还是可以继续使用Primary之类的注解的,并且这多个Qualifier还可以一块注入到集合中:
@Configuration
@ComponentScan
public class DemoApp {
@Bean
@Qualifier("s1")
public IService service1(){
return new Service1();
}
@Bean
@Qualifier("s1")
@Primary
public IService service2(){
return new Service2();
}
@Bean
public Service3 service3(@Qualifier("s1") IService iService){
return new Service3(iService);
}
}
@Service
public class Service4 {
@Autowired
@Qualifier("s1")
private Set<IService> serviceSet;
}
}
还可以把泛型类型当成是一种限定符:
public interface IService<T> {
}
public class IntegerService implements IService<Integer> {
}
public class StringService implements IService<String> {
}
@Component
public class Service6 {
/**这里注入的是StringService*/
@Autowired
private IService<String> s1;
/**这里注入的是IntegerService*/
@Autowired
private IService<Integer> s2;
public IService<String> getS1(){
return s1;
}
public IService<Integer> getS2(){
return s2;
}
}
JSR250注解,它是优先按照bean的名字进行注入,由CommonAnnotationBeanPostProcessor进行处理。
本文系作者在时代Java发表,未经许可,不得转载。
如有侵权,请联系nowjava@qq.com删除。