admin管理员组

文章数量:1624332

  • Autowired等注解
    • Spring依赖注入之@Autowired、@Qualifier、@Primary、@Priority注解用法
    • Spring依赖注入之@Autowired、@Qualifier、@Primary、@Priority注解原理(上)
    • Spring依赖注入之@Autowired、@Qualifier、@Primary、@Priority注解原理(下)
  • Value注解
    • 依赖注入之@Value原理(整体流程)
    • 依赖注入之@Value原理(获取value值)
    • 依赖注入之@Value原理(placeholder解析)
    • 依赖注入之@Value原理(SpEL表达式解析)
  • Lookup注解
    • Spring Boot依赖注入之Lookup注解

@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=false

required默认是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<Dependent> dependentList;

    @Autowired
    private Set<Dependent> dependentSet;

    @Autowired
    private  Map<String, Dependent> dependentMap;
}

实际上是分为三种情况来处理的:Map、Collection子接口、数组,而对于Collection子接口、数组两种情况,实际是先获取Map再转成对应的类型的。这里的实现比较tricky,限制比较多

Map

Field的类型必须是参数化Map<String, xxx>,也就是必须是Map类型(不能是HashMap、也不能是原型Map),并且Map的key必须是String类型,Value可以是各种Bean的类型

Collection子接口

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<Dependent> dependentList;

    private Set<Dependent> dependentSet;

    private  Map<String, Dependent> dependentMap;

    @Autowired
    public Comp(Dependent[] dependentArr, List<Dependent> dependentList, Set<Dependent> dependentSet, Map<String, Dependent> 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<Dependent> dependentList;

    private Set<Dependent> dependentSet;

    private  Map<String, Dependent> dependentMap;

    @Autowired
    public void inject(Dependent[] dependentArr, List<Dependent> dependentList, Set<Dependent> dependentSet, Map<String, Dependent> 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注解(任何Nullable注解,只要名字是Nullable,区分大小写)也可以用来达到和@Autowired的required=false一样的效果,可以用在field上、也可以用在方法参数上

@Component
public class Comp {

    @Autowired
    @Nullable
    private Dependent[] dependentArr;

    @Autowired
    private Optional<Dependent> dependent;
}
@Component
public class Comp {
    private Dependent[] dependentArr;
    private Dependent dependent;

    @Autowired
    public void inject(@Nullable Dependent[] dependentArr,
                       Optional<Dependent>  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接口或都没有实现该接口,再比较order
  • order获取顺序为: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在前

本文标签: 注解AutoWiredSpringqualifierPriority