spring-装配注解

1. @Autowird

1. 作用

实现依赖注入,spring容器会对bean中所有字段、方法进行遍历,标注有@Autowired注解的,都会进行注入。

2. 定义

@Target({ElementType.CONSTRUCTOR, ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Autowired {

	/**
	 * Declares whether the annotated dependency is required.
	 * <p>Defaults to {@code true}.
	 */
	boolean required() default true;

}

可以用在构造器、方法、方法参数、字段、注解上。

参数:
required:标注的对象是否必须注入,可能这个对象在容器中不存在,如果为true的时候,找不到匹配的候选者就会报错,为false的时候,找不到也没关系 。

处理 @Autowird 的类:org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor

3. 查找候选者的过程

@Autowired标注在字段上面:假定字段类型为一个自定义的普通的类型,候选者查找过程如下:

@Autowired标注在方法上或者方法参数上面:假定参数类型为为一个自定义的普通的类型,候选者查找过程如下:

上图中深色的表示方法注入和字段注入查找过程的不同点。

上图中展示的是方法中只有一个参数的情况,如果有多个参数,就重复上面的过程,直到找到所有需要注入的参数。

总结:按类型找->通过限定符@Qualifier过滤->@Primary->@Priority->根据名称找(字段名称或者方法名称)

4. 注入到 collection 或者 map

1. 注入到 collection

@Autowired
private List<AnimalService> list;

会将所有 AnimalService 类型的 bean 注入到 list,可以通过 @Qualifier 过滤,只注入需要的 bean。@Primary 不会过滤。

2. 注入到 Map

@Autowired
@Qualifier
private Map<String, AnimalService> map;

将所欲 AnimalService 类型的 bean 注入 map,作为 value,而对应的 key 是 bean 的名字。同样可以使用 @Qualifier 过滤。

5. 注入方式

通过源码,@Autowired 的作用域可以看到 @Target({ElementType.CONSTRUCTOR, ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD, ElementType.ANNOTATION_TYPE}),是可以用在这些上面的。

先随便定义一个 bean,用来做被注入的对象。

@Component
public class Dog {
    public void run(){
        System.out.println("狗子跑啊");
    }
}

1,属性注入

@Service
public class FieldService {

    @Autowired
    private Dog dog;

    public void test(){
        dog.run();
    }
}

对属性做注入

优点:

  1. 实现简单,使用简单

缺点:

  1. 无法注入 final 变量
  2. 循环依赖问题,由于 spring 使用三级循环解决了 set 方法注入时的循环依赖问题,因此如果存在单例的循环依赖也是可以通过编译的,但是实际上我们要尽量避免循环依赖问题。

2,set 方法注入

@Component
public class SetterService {
    
    private Dog dog;

    @Autowired
    public void setDog(Dog dog) {
        this.dog = dog;
    }

    public void test(){
        dog.run();
    }
}

setter注入是指将一个类的依赖通过设置一个公共的setter方法注入到该类中,这样就能够让该类使用这个依赖。setter方法通常在类中定义为public,并且以set开头,接着是一个单词,表示注入的属性的名称。
方法注入:如果方法中有实体参数,会对方法里面的参数进行装配

优点

  1. 完全符合单一职责的设计原则,因为每个Setter只针对一个对象。

缺点

  1. 和属性注入一样,无法注入 final 属性
  2. 注入对象可能被更改,setter 方法,可能随时被调用。

3,构造器注入

@Component
public class ConstructService {

    private Dog dog;

    @Autowired
    public ConstructService(Dog dog){
        this.dog = dog;
    }

    public void test(){
        dog.run();
    }

}

构造方法注入是Spring官方从4.x之后推荐的注入方式,如果构造方法只有一个,那么 @Autowired 不是必须的,会对构造器的参数进行注入。

优点

  1. 可注入 final 属性,由于构造方法只会在对象创建的时候执行一次,避免了像Setter注入那样,不存在注入对象被随时(调用)修改的情况。
  2. 注入对象被完全初始化

缺点

  1. 循环依赖问题无法解决,其实我们应该尽量避免循环依赖问题,从这方面看这不能算个缺点。

2. @Resource

1. 作用

和@Autowired注解类似,也是用来注入依赖的对象的,spring容器会对bean中所有字段、方法进行遍历,标注有@Resource注解的,都会进行注入。

2. 定义

javax.annotation.Resource
 
@Target({TYPE, FIELD, METHOD})
@Retention(RUNTIME)
public @interface Resource {
    String name() default "";
    ..其他不常用的参数省略
}

这个注解是javax中定义的,并不是spring中定义的注解。

从定义上可以见,这个注解可以用在任何类型上面、字段、方法上面。

注意点:

用在方法上的时候,方法参数只能有一个。

处理 @Resource 源码:org.springframework.context.annotation.CommonAnnotationBeanPostProcessor

3. 查找候选者过程

先按Resource的name值作为bean名称找->按名称(字段名称、方法名称、set属性名称)找->按类型找->通过限定符@Qualifier过滤->@Primary->@Priority->根据名称找(字段名称或者方法参数名称)

将相当于在 @Autowired 前面加了通过 bean 名称查找,找不到就按 @Autowired 来

3. @Qualifier

1. 限定符

这个单词的意思是:限定符。

可以在依赖注入查找候选者的过程中对候选者进行过滤。

2. 定义

@Target({ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER, ElementType.TYPE, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface Qualifier {
    //标记名称
    String value() default "";
}

由于使用了 @Inherited 注解,所以 @Qualifier 注解会被子类继承

3. 实例

定义几个 bean

@Component
@Qualifier("subLevel")
public class ProgressPaymentJDKServiceImpl implements ProgressPaymentLevelService {}


@Component
@Qualifier("subLevel")
public class ProgressPaymentFBDWServiceImpl implements ProgressPaymentLevelService {}

@Component
@Qualifier("subLevel")
public class ProgressPaymentDWGCServiceImpl implements ProgressPaymentLevelService {}

@Component
public class ProgressPaymentBDServiceImpl implements ProgressPaymentLevelService {}

使用时候过滤

@Autowired
@Qualifier("subLevel")
private List<ProgressPaymentLevelService> progressPaymentLevelServiceList;

@Autowired
private List<ProgressPaymentLevelService> progressPaymentLevelServiceList1;

4. @Primary

1. 作用

注入依赖的过程中,当有多个候选者的时候,可以指定哪个候选者为主要的候选者。

2. 定义

@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Primary {
 
}
posted @ 2023-08-24 10:44  primaryC  阅读(20)  评论(0编辑  收藏  举报