Spring Boot2.x-05Spring Boot基础-使用注解完成依赖注入

举报
小工匠 发表于 2021/09/10 23:14:49 2021/09/10
【摘要】 文章目录 概述@Autowired注解@Autowired的匹配原则@Autowired的 required 属性使用@Primary 和@Qualifier消除@Autowired的歧义@Pri...

概述

Spring Boot2.x-04Spring Boot基础-使用注解装配bean 中讲了如何将Bean装载到IoC容器中,这里我们说下Bean之间的依赖关系,当然了还是基于注解的方式。

xml的方式去描述Bean之间的依赖关系,请参考以前的博客

Spring-bean之间的关系

Spring-基于注解的配置[02自动装载bean]


@Autowired注解

举个例子: Manager可以安排Engineer去根据Engineer的类型做不同的工作

在这里插入图片描述

接口Engineer的接口方法是coding

package com.artisan.springbootmaster.di.intf;

public interface Engineer {

    void coding();
}

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

假设有个Java程序猿,实现Engineer接口

package com.artisan.springbootmaster.di.intf.impl;


import com.artisan.springbootmaster.di.intf.Engineer;
import org.springframework.stereotype.Service;

@Service
public class JavaEnginerr implements Engineer {

    @Override
    public void coding() {
        System.out.println("Java Engineer works");
    }
}

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

我们在实现类JavaEnginerr 上使用@Service注解,使其成为一个受Spring容器管理的bean。


接下来,我们来看下Manager类

package com.artisan.springbootmaster.di;

import com.artisan.springbootmaster.di.intf.Engineer;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
public class Manager {

    @Autowired
    Engineer engineer;

    public void arrange(){
        engineer.coding();
    }

}


  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

可以通过arrange方法安排engineer工作。 这里Engineer 通过@Autowired让IoC容器自动注入进来。

接着我们使用Java类的方式来初始化IoC容器,通过@Configuration标注其是一个配置类 ,通过ComponetScan来扫描基包下面的标注了注解的类,使其成为受Spring IoC容器托管的bean,方便注入

package com.artisan.springbootmaster.di;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

@Configuration
@ComponentScan(basePackages = "com.artisan.springbootmaster.*")
public class Config {

}


  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

最后,加载Java类的配置,主要是依靠 AnnotationConfigApplicationContext,启动容器获取bean,并调用对应的方法

package com.artisan.springbootmaster.di;

import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class DITest {

    public static void main(String[] args) {
        ApplicationContext applicationContext = new AnnotationConfigApplicationContext(Config.class);
        Manager manager =  applicationContext.getBean(Manager.class);
        manager.arrange();
    }
}

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

运行

23:04:08.018 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Returning cached instance of singleton bean 'manager'
Java Engineer works


  
 
  • 1
  • 2
  • 3

@Autowired会根据属性的类型( by type )找到对应的 Bean 进行注入。
在这里插入图片描述

通过结果可以知道,通过注解@Autowired 成功的将JavaEngierr注入到了Manager实例中。


@Autowired的匹配原则

上面这个例子中@Autowired的用法很简单,我们继续来看下@Autowired

当然了,Engineer可能有多个,比如又来了个AndroidEngineer

package com.artisan.springbootmaster.di.intf.impl;

import com.artisan.springbootmaster.di.intf.Engineer;
import org.springframework.stereotype.Service;


@Service
public class AndroidEngineer implements Engineer {

    @Override
    public void coding() {
        System.out.println("Android Engineer works");
    }
}


  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

这是IDEA中可以看到,有提示报错了
在这里插入图片描述

让我们继续运行下DITest,抛出了异常

 No qualifying bean of type 'com.artisan.springbootmaster.di.intf.Engineer' available: expected single matching bean but found 2: androidEngineer,javaEnginerr


  
 
  • 1
  • 2

意思很明显,@Autowired根据类型来匹配Engineer,却发现有2个bean都是Engineer类型 ,这下子Spring不知道注入哪个了。

@Autowired的匹配原则:根据类型找到对应的 Bean,如果对应类型的 Bean 不是唯一 的,那么会继续根据其属性名称和 Bean 的名称进行匹配。如果匹配上,就会使用该 Bean,如果还无法匹配,就会抛出异常。

所以根据上面的原则,比较挫的一个办法(这里只是说可以这么改,但是肯定不推荐这么改

既然是两个,那我就让bean的名字一样呗

  • 方法一:Manager中的Engineer engineer保持不变,给这两个Engineer中的任意一个标注@Service(value "engineer"),指定其bean的名字为engineer,这样根据name就匹配上了,同样不会抛出异常。测试通过。
  • 方法二:Manager中的Engineer engineer改为这两个bean的任意一个名字,@Service标注的实现类Bean的名字为默认第一个字母小写其余保持不变,这样name也能匹配上,同样不会抛出异常。测试通过。

在这里插入图片描述

结果
在这里插入图片描述

这里只是举例验证下Spring @Autowired的匹配规则,实际工作中并不推荐这么改。。。。


@Autowired的 required 属性

@Autowired 是一个默认必须找到对应 Bean 的注解,如果不能确定其标注属性一定会存在并且允许这个被标注的属性为 null , 那么你可以配置@Autowired 属性 required 为 false.

@Autowired既可以标注在属性上,也可以标注在方法上

 @Autowired(required = false)

  
 
  • 1

使用@Primary 和@Qualifier消除@Autowired的歧义

上面通过修改name,使其name保持一致的方式消除了歧义,可以正常的注入,不过并不推荐。

@Primary 不推荐使用

也可以使用@Primary,当然了,也不推荐这么干。 因为另外一个类也可以标注@Primary,Spring又无法知道注入哪个了。

注解@Primary是修改优先权的注解,像上面的两个例子,有2个beanandroidEngineer,javaEnginerr, 如果我们仅在JavaEnginerr这个类上标注@Primary,意思是告诉Spring IoC 容器 , 当发现有多个同样类型的 Bean ,请优先使用标注了@Primary的这个bean进行注入。

在这里插入图片描述

结果:
在这里插入图片描述


@Qualifier推荐使用

@Qualifier的value属性定义bean的名,该名称将会和@Autowired 组合在一起,通过类型和名称一起找到 Bean。Spring IoC容器中Bean 名称是唯一的标识,通过这个就可以消除歧义了

在这里插入图片描述

结果

在这里插入图片描述

即使 JavaEnginerr标注了@Primary,但是由于使用了@Qualifier,注入的依然是androidEngineer.


在构造函数/方法中使用@Autowired

上面的例子,我们是在属性上使用的@Autowired.
如果使构造函数呢?

我们改造下Manager

package com.artisan.springbootmaster.di;

import com.artisan.springbootmaster.di.intf.Engineer;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;

@Component
public class Manager {

    Engineer engineer;

    public void arrange(){
        engineer.coding();
    }


    public Manager(@Autowired @Qualifier("javaEnginerr") Engineer engineer){
        this.engineer = engineer;
    }
}


  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 取消标注在属性上的注解
  • 在构造函数上增加注解,使用方法一样。
  • 如果仅有一个类型的Bean, @Qualifier就没有必要加上了。

运行

在这里插入图片描述

文章来源: artisan.blog.csdn.net,作者:小小工匠,版权归原作者所有,如需转载,请联系作者。

原文链接:artisan.blog.csdn.net/article/details/83421253

【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。