@Autowired注解可以声明一个bean依赖的其他bean,spring在创建bean时会将这些依赖的bean注入进来,涉及到的注解有@Autowired、@Value、@Qualifier、@Primary、@Priority,本节主要介绍@Autowired、@Qualifier、@Primary、@Priority这几个注解的用法
@Autowired注解如下
@Target({ElementType.CONSTRUCTOR, ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@documented
public @interface Autowired {
boolean required() default true;
}
required字段表示是否必须注入。这个注解可以用在很多地方:构造器、方法、参数、属性、注解上。在使用上会涉及多个bean会怎么选择、如何指定autowire优先级等问题。下面就这些使用上的问题具体分析
1、用在属性上这是一个最常用方式
a、对属性进行注入@Component
public class Dependent {
}
@Component
public class Comp {
@Autowired
private Dependent dependent;
}
Spring启动后Comp这个bean的dependent属性就会被注入依赖。
b、设置required=falserequired默认是true,当找不到这个bean时会抛出异常;required=false,当找不到这个bean,则忽略不处理。如下:
@Component
public class Comp {
@Autowired(required = false)
private Dependent dependent = new Dependent();
}
此时如果Spring不存在Dependent类型的bean,则为一个默认值,如果存在则会注入进来。
c、对数组、List、Set、Map属性进行注入还可以对数组、List、Set、Map类型的属性注入依赖。如下:
public class Dependent {
}
@Configuration(proxyBeanMethods = false)
public class DepConfig {
@Bean
public Dependent d1() {
return new Dependent();
}
@Bean
public Dependent d2() {
return new Dependent();
}
}
@Component
public class Comp {
@Autowired
private Dependent[] dependentArr;
@Autowired
private List dependentList;
@Autowired
private Set dependentSet;
@Autowired
private Map dependentMap;
}
实际上是分为三种情况来处理的:Map、Collection子接口、数组,而对于Collection子接口、数组两种情况,实际是先获取Map再转成对应的类型的。这里的实现比较tricky,限制比较多
MapField的类型必须是参数化Map
Field的类型必须是Collection子接口(不能是子类)。处理分成了两步:第一步获取上述Map,第二步通过TypeConverter将Map转成对应Collection子接口类型。默认情况下TypeConverter能处理Map到List、Map到Set的转换,因此Field是List、Set是可以的的;默认情况下TypeConverter不能处理Typeconverter到SortedSet的转换,因此会抛出类型转换异常,但可以通过扩展TypeConverter将Map转换成SortedSet。对于结果是List的,还会根据优先级进行排序
数组Field的类型是数组的情况,处理也是分为两步:第一步获取上述Map,第二步通过TypeConverter将Map转成数组,然后根据优先级进行排序。
2、用在构造函数上@Component
public class Comp {
private Dependent[] dependentArr;
private List dependentList;
private Set dependentSet;
private Map dependentMap;
@Autowired
public Comp(Dependent[] dependentArr, List dependentList, Set dependentSet, Map dependentMap) {
this.dependentArr = dependentArr;
this.dependentList = dependentList;
this.dependentSet = dependentSet;
this.dependentMap = dependentMap;
}
}
3、用在方法上
一般的用法是标注再setter上,但实际上对方法名没有限制、参数个数也没有限制、也不要求是public
@Component
public class Comp {
private Dependent[] dependentArr;
private List dependentList;
private Set dependentSet;
private Map dependentMap;
@Autowired
public void inject(Dependent[] dependentArr, List dependentList, Set dependentSet, Map dependentMap) {
this.dependentArr = dependentArr;
this.dependentList = dependentList;
this.dependentSet = dependentSet;
this.dependentMap = dependentMap;
}
}
4、用在参数上
@Autowired使用在方法参数上大部分情况下会忽略,只有两种情况会生效
spring test覆盖方法上的required参数
主要看第二种情况。方法或构造函数上的@Autowired里的required属性会对方法的所有参数生效,如果某些与其他参数不同的话,可以单独设置。并且为了这个方法/构造函数能够被识别到,某些情况下方法/构造函数上必须要有@Autowired注解(具体细节原理部分再分析)。如下
@Component
public class Comp {
private Dependent[] dependentArr;
private Dependent dependent;
@Autowired
public void inject(Dependent[] dependentArr,
@Autowired(required = false) @Qualifier("ddd") Dependent dependent) {
this.dependentArr = dependentArr;
this.dependent = dependent;
}
}
5、Optional和@Nullable
java1.8的Optional和@Nullable注解(org.springframework.lang.Nullable)也可以用来达到和@Autowired的required=false一样的效果,可以用在field上、也可以用在方法参数上
@Component
public class Comp {
@Autowired
@Nullable
private Dependent[] dependentArr;
@Autowired
private Optional dependent;
}
@Component
public class Comp {
private Dependent[] dependentArr;
private Dependent dependent;
@Autowired
public void inject(@Nullable Dependent[] dependentArr,
Optional dependent) {
this.dependentArr = dependentArr;
dependent.ifPresent((dep) -> this.dependent = dep);
}
}
6、@Qualifier、@Primary、@Priority
当@Autowired只需要一个bean而存在多个同类型的bean,可以通过@Qualifier和@Primary注解来指定autowire哪一个,也可以通过@Priority指定优先级,Spring取优先级最高的(值最小的)
@Qualifier跟@Autowired一起使用,指定autowire的beanName
@Configuration(proxyBeanMethods = false)
public class DepConfig {
@Bean
public Dependent d1() {
return new Dependent();
}
@Bean
public Dependent d2() {
return new Dependent();
}
}
@Component
public class Comp {
@Autowired
@Qualifier("d1")
private Dependent dependent;
}
@Primary跟@Component或者@Bean一起使用,指定当存在多个类型的bean时,优先使用这一个(@Primary只能存在一个,有多个会抛出异常)
@Configuration(proxyBeanMethods = false)
public class DepConfig {
@Bean
public Dependent d1() {
return new Dependent();
}
@Bean
@Primary
public Dependent d2() {
return new Dependent();
}
}
@Component
public class Comp {
@Autowired
private Dependent dependent;
}
@Priority(javax.annotation.Priority)注解只能用在类上
@Target({TYPE,PARAMETER})
@Retention(RUNTIME)
@documented
public @interface Priority {
int value();
}
bean定义
public class Dependent {
}
@Component
@Priority(2)
class DependentA extends Dependent {}
@Component
@Priority(0)
class DependentB extends Dependent {}
Comp将会注入DependentB这个bean
@Component
public class Comp {
@Autowired
private Dependent dependent;
}
7、bean排序
当注入的类型为数组或List时,会涉及排序问题,排序比前面的取最高优先级要复杂得多(前面只考虑@Priority注解),Spring的排序涉及到
PriorityOrdered接口Ordered接口@Priority注解@Order注解
不同Bean进行比较时,规则如下:
实现了PriorityOrdered接口优先,都实现了PriorityOrdered接口或都没有实现该接口,再比较orderorder获取顺序为:PriorityOrdered#getOrder、Ordered#getOrder、@Order、@Priority
@Component
@Order(1)
class DependentA extends Dependent implements Ordered {
@Override
public int getOrder() {
return 3;
}
}
@Component
@Order(2)
@Priority(4)
class DependentB extends Dependent {}
@Component
public class Comp {
@Autowired
private Dependent[] dependent;
}
DependentA的order=3,DependentB的order=2,DependentB在前



