spring成神之路第二十一篇:注解实现依赖注入(@Autowired、@Resource、@Primary、@Qulifier)...

  先来看几个问题

  1. 通过注解的方式注入依赖对象,介绍一下你知道的几种方式

  2. @Autowired和@Resource有何区别

  3. 说一下@Autowired查找候选者的过程

  4. 说一下@Resource查找候选者的过程

  5. @Qulifier有哪些用法?

  6. @Qulifier加在类上面是干什么用的?

  7. @Primary是做什么的?

  8. 泛型注入用过么?

这些问题如果你都ok,那么恭喜你,很厉害。

本文内容

  1. 介绍spring中通过注解实现依赖注入的所有方式

  • @Autowired注解

  • @Qualifier注解

  • @Resource注解

  • @Primary注解

  • @Bean中注入的几种方式

  1. 将指定类型的所有bean,注入到集合中

  2. 将指定类型的所有bean,注入到map中

  3. 注入泛型

  4. 依赖注入源码方面的一些介绍

本文内容比较多,所有知识点均有详细案例,大家一定要敲一遍,加深理解。

@Autowired:注入依赖对象

作用

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

看一下其定义:

@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的时候,找不到也没关系 。

@Autowire查找候选者的过程

查找过程有点复杂,看不懂的可以先跳过,先看后面案例,本文看完之后,可以回头再来看这个过程。

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

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

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

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

将指定类型的所有bean注入到Collection

如果被注入的对象是Collection类型的,可以指定泛型的类型,然后会按照上面的方式查找所有满足泛型类型所有的bean

将指定类型的所有bean注入到Map

如果被注入的对象是Map类型的,可以指定泛型的类型,key通常为String类型,value为需要查找的bean的类型,然后会按照上面方式查找所有注入value类型的bean,将bean的name作为key,bean对象作为value,放在HashMap中,然后注入。

@Autowired查找候选者可以简化为下面这样
按类型找->通过限定符@Qualifier过滤->@Primary->@Priority->根据名称找(字段名称或者方法名称)

概括为:先按类型找,然后按名称找

案例1:@Autowired标注在构造器上,通过构造器注入依赖对象

Service1
package com.javacode2018.lesson001.demo26.test0;

import org.springframework.stereotype.Component;

@Component
public class Service1 {
}
Service2
package com.javacode2018.lesson001.demo26.test0;

import org.springframework.stereotype.Component;

@Component
public class Service2 {
    private Service1 service1;

    public Service2() { //@1
        System.out.println(this.getClass() + "无参构造器");
    }

    public Service2(Service1 service1) { //@2
        System.out.println(this.getClass() + "有参构造器");
        this.service1 = service1;
    }

    @Override
    public String toString() { //@2
        return "Service2{" +
                "service1=" + service1 +
                '}';
    }
}

Service2中依赖于Service1,有2个构造方法

@1:无参构造器

@2:有参构造器,可以通过这个传入依赖的Service1

@3:重写了toString方法,一会打印测试的时候方便查看

来个总的配置文件
package com.javacode2018.lesson001.demo26.test0;

import org.springframework.context.annotation.ComponentScan;

@ComponentScan //@1
public class MainConfig0 {
}

@1:会自动扫描当前类所在的包,会将Service1和Service2注册到容器。

来个测试用例
package com.javacode2018.lesson001.demo26;

import com.javacode2018.lesson001.demo26.test0.MainConfig0;
import org.junit.Test;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class InjectTest {

    @Test
    public void test0() {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MainConfig0.class);
        for (String beanName : context.getBeanDefinitionNames()) {
            System.out.println(String.format("%s->%s", beanName, context.getBean(beanName)));
        }
    }

}

main方法中启动容器,加载MainConfig0配置类,然后输出容器中所有的bean

运行部分输出
class com.javacode2018.lesson001.demo26.test0.Service2无参构造器
service1->com.javacode2018.lesson001.demo26.test0.Service1@4a94ee4
service2->Service2{service1=null}

输出中可以看出调用了Service2的无参构造器,service2中的service1为null

通过@Autowired指定注入的构造器

在Service2有参有参构造器上面加上@Autowired注解,如下:

@Autowired
public Service2(Service1 service1) {
    System.out.println(this.getClass() + "有参构造器");
    this.service1 = service1;
}
再次运行test0()
class com.javacode2018.lesson001.demo26.test0.Service2有参构造器
service1->com.javacode2018.lesson001.demo26.test0.Service1@4ec4f3a0
service2->Service2{service1=com.javacode2018.lesson001.demo26.test0.Service1@4ec4f3a0}

Service2有参构造器被调用了,service2中的service1有值了。

案例2:@Autowired标注在方法上,通过方法注入依赖的对象

Service1
package com.javacode2018.lesson001.demo26.test1;

import org.springframework.stereotype.Component;

@Component
public class Service1 {
}
Service2
package com.javacode2018.lesson001.demo26.test1;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
public class Service2 {
    private Service1 service1;

    @Autowired
    public void injectService1(Service1 service1) { //@1
        System.out.println(this.getClass().getName() + ".injectService1()");
        this.service1 = service1;
    }

    @Override
    public String toString() {
        return "Service2{" +
                "service1=" + service1 +
                '}';
    }
}

@1:方法上标注了@Autowired,spring容器会调用这个方法,从容器中查找Service1类型的bean,然后注入。

来个总的配置文件
package com.javacode2018.lesson001.demo26.test1;

import org.springframework.context.annotation.ComponentScan;

@ComponentScan
public class MainConfig1 {
}
来个测试用例

InjectTest中加个方法

@Test
public void test1() {
    AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MainConfig1.class);
    for (String beanName : context.getBeanDefinitionNames()) {
        System.out.println(String.format("%s->%s", beanName, context.getBean(beanName)));
    }
}
运行输出
com.javacode2018.lesson001.demo26.test1.Service2.injectService1()
service1->com.javacode2018.lesson001.demo26.test1.Service1@9597028
service2->Service2{service1=com.javacode2018.lesson001.demo26.test1.Service1@9597028}

通过injectService1方法成功注入service1

案例3:@Autowired标注在setter方法上,通过setter方法注入

上面2种通过构造器,和通过普通的一个方法注入,不是很常见,可以将@Autowired标注在set方法上面,来注入指定的对象

Service1
package com.javacode2018.lesson001.demo26.test2;

import org.springframework.stereotype.Component;

@Component
public class Service1 {
}
Service2
package com.javacode2018.lesson001.demo26.test2;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
public class Service2 {

    private Service1 service1;

    @Autowired
    public void setService1(Service1 service1) { //@1
        System.out.println(this.getClass().getName() + ".setService1方法");
        this.service1 = service1;
    }

    @Override
    public String toString() {
        return "Service2{" +
                "service1=" + service1 +
                '}';
    }
}

@1:标准的set方法,方法上使用了 @Autowired,会通过这个方法注入Service1类型的bean对象。

来个总的配置文件
package com.javacode2018.lesson001.demo26.test2;

import org.springframework.context.annotation.ComponentScan;

@ComponentScan
public class MainConfig2 {
}
来个测试用例
@Test
public void test2() {
    AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MainConfig2.class);
    for (String beanName : context.getBeanDefinitionNames()) {
        System.out.println(String.format("%s->%s", beanName, context.getBean(beanName)));
    }
}
运行输出
com.javacode2018.lesson001.demo26.test2.Service2.setService1方法
service1->com.javacode2018.lesson001.demo26.test2.Service1@6069db50
service2->Service2{service1=com.javacode2018.lesson001.demo26.test2.Service1@6069db50}

案例4:@Autowired标注在方法参数

Service1
package com.javacode2018.lesson001.demo26.test3;

import org.springframework.stereotype.Component;

@Component
public class Service1 {
}
Service2
package com.javacode2018.lesson001.demo26.test3;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
public class Service2 {

    private Service1 service1;

    @Autowired
    public void injectService1(Service1 service1, String name) { //@1
        System.out.println(String.format("%s.injectService1(),{service1=%s,name=%s}", this.getClass().getName(), service1, name));
        this.service1 = service1;
 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值