全注解下的SpringIoc 续1-依赖注入

news2024/12/27 12:59:53

上篇文章介绍了ioc的基本用法和@ComponentScan注解的使用,这篇文章我们来看看依赖注入的部分。
提起依赖注入,想必大家肯定会想到@Autowired注解,的确,它是我们用的最多的一个。
还记得容器的顶级接口BeanFactory 吗,它定义了获取bean的几个方法,主要是基于类型和基于名称来获取bean,而这里即将要介绍的@Autowired注解便是首先基于类型来获取bean的。

下面我们来看个例子,有个人需要让自己的宠物来帮自己做些事情,这里我们先定义人和动物的接口:

public interface Person {
    /**
     * 使用动物服务
     */
    void service();
}

public interface Animal {
    /**
     * 动物的使用方法
     */
    void use();
}

然后分别定义它们的实现类:

@Component
public class DiBusinessPerson implements Person {

    @Autowired
    private Animal cat;

    @Override
    public void service() {
        this.cat.use();
    }
    
@Component
@Slf4j
public class DiCat implements Animal {
    @Override
    public void use() {
        log.warn("猫【{}】是抓老鼠用的。", DiCat.class.getSimpleName());
    }
}

注意:对于DiBusinessPerson 类中的成员变量dog,我们使用了@Autowired注解标记,这样spring容器在创建这个bean时,会自动将其依赖的Animal 注入进来,也就是spring会帮助我们创建Animal 的实例,并将其赋值给dog,完成依赖注入。
然后我们还是定义一个配置类,用来配置扫描规则;

@Configuration
@ComponentScan(basePackages = {"com.zzm.iocdi"})
public class DiAppConfig {

}

最后创建测试类,运行main方法看下效果:

@Slf4j
public class IocDiTest {
    public static void main(String[] args) {
        ApplicationContext context = new AnnotationConfigApplicationContext(DiAppConfig.class);
        Person person = context.getBean(DiBusinessPerson.class);
        person.service();
    }
}

在这里插入图片描述
从日志可以看到,cat对象已经被成功注入到DiBusinessPerson对象中,完成了依赖注入。

歧义性问题

但是,如果这个人想要养多只不同种类的宠物时,要怎么办呢?假设现在想再养只狗狗,那么首先,我们需要创建狗狗的类,然后在DiBusinessPerson类中再添加一只狗狗的变量

@Component
@Slf4j
public class DiDog implements Animal {
    @Override
    public void use() {
        log.warn("狗【{}】是看门用的。", DiDog.class.getSimpleName());
    }
}

@Component
public class DiBusinessPerson implements Person {
    @Autowired
    private Animal cat;

    @Autowired
    private Animal dog;

    @Override
    public void service() {
        this.cat.use();
        this.dog.use();
    }

}

再次运行测试类的main方法,可以看到如下日志:
在这里插入图片描述
发现程序报错了,原因是Animal接口存在两个实现类,@Autowired注解根据Animal类型找到了两只动物,它不知道应该要注入哪一个,所以出现了这个错误。
为了解决这个问题,我们首先再回顾一下@Autowired注解的应用机制:

Created with Raphaël 2.3.0 开始 根据类型匹配bean 根据类型是否可以准确匹配到? 注入成功 结束 根据名称匹配bean 根据名称是否可以准确匹配到? 是否可以为空? 抛出异常,注入失败 yes no yes no yes no

因为我们没有特殊设置@Autowired注解的属性,所以会按照它的默认机制,也就是上述流程进行bean的注入,它默认被注入的对象是不能为空的,所以这里就抛出了异常。

方案1

现在,我们来解决这个问题,既然它根据类型匹配到了多个宠物(猫、狗),那么我们让它根据名称可以定位到,修改下DiBusinessPerson类中猫和狗的变量名称,和对应的bean的名称保持一致,如下:

@Component
public class DiBusinessPerson implements Person {
    @Autowired
    private Animal diCat;

    @Autowired
    private Animal diDog;

    @Override
    public void service() {
        this.diCat.use();
        this.diDog.use();
    }

}

然后再次运行程序,可见如下日志,表示已经注入成功了。
在这里插入图片描述
但是,这种写法业界内并不推荐,因为成员变量的名称被限制,怎么都感觉不靠谱,所以下面介绍另外一种方案。

方案2

@Primary注解的使用。
该注解用于修改注入优先级的,它会使得被标记的对象优先注入。
这里我们以猫对象为例,修改代码如下:

@Primary
@Component
@Slf4j
public class DiCat implements Animal {
    @Override
    public void use() {
        log.warn("猫【{}】是抓老鼠用的。", DiCat.class.getSimpleName());
    }
}

@Component
public class DiBusinessPerson implements Person {
    @Autowired
    private Animal cat;

    @Autowired
    private Animal dog;

    @Override
    public void service() {
        this.cat.use();
        this.dog.use();
    }

}

然后再次运行程序,可见如下日志:
在这里插入图片描述
程序没有报错了,注入已经成功了。但是,有没有发现,这两个宠物都变成了猫,我们原先的设想是一只猫、一只狗,现在因为猫对象里面使用了@Primary注解提升了注入优先级,所以@Autowired注解在注入时就会优先选择猫。
很显然,这并不是我们想要的,为了达到目的,这里引出了这个注解,@Qualifier
它的value属性可以让我们指定需要注入的bean名称,从而和@Autowired相互配合,使我们得到正确的结果。
修改代码如下:

@Component
public class DiBusinessPerson implements Person {
    @Autowired
    @Qualifier("diCat")
    private Animal cat;

    @Autowired
    @Qualifier("diDog")
    private Animal dog;

    @Override
    public void service() {
        this.cat.use();
        this.dog.use();
    }

}

然后再次运行程序,可见如下日志:
在这里插入图片描述
可以看到,猫和狗都各司其职了。

带有参数的构造方法类的装配

上面的例子都是基于这些类的构造方法是没有参数的,那么,有参数的构造方法的类要怎么注入呢?让我们一起来看看。。。
修改DiBusinessPerson类的代码,使其包含有参数的构造方法,代码如下:

@Component
public class DiBusinessPerson implements Person {
    @Autowired
    @Qualifier("diCat")
    private Animal cat;

    private Animal dog;
    
	@Autowired(required = false)
    private Animal dog2;

    private Animal cat2;

    public DiBusinessPerson(@Autowired @Qualifier("diDog") Animal dog){
        this.dog = dog;
    }

    @Override
    public void service() {
        this.cat.use();
        this.dog.use();
        this.cat2.use();
    }

    @Autowired
    @Qualifier("diCat")
    public void setAnimal(Animal animal) {
        this.cat2 = animal;
    }
}

可以看到,这里将@Autowired @Qualifier两个注解用来了构造方法的参数和自定义方法上,所以spring在创建DiBusinessPerson 对象调用构造方法时,也会将需要的狗狗实例注入进来。这两个注解也可以用于自定义的方法参数之上,感兴趣的小伙伴可以自行尝试下。
然后我们再次运行main方法,得到如下日志:
在这里插入图片描述
可见是注入成功的。
另外,@Autowired注解默认是必须要匹配到一个值的,不然就会报错,但是我们可以设置其允许为空,如dog2属性的注入。

下次写关于bean的生命周期的,敬请期待。。。。。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/455864.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

函数栈帧的创建和销毁【汇编语言理解】

🌹作者:云小逸 📝个人主页:云小逸的主页 📝Github:云小逸的Github 🤟motto:要敢于一个人默默的面对自己,强大自己才是核心。不要等到什么都没有了,才下定决心去做。种一颗树,最好的时间是十年前…

echarts双Y轴对齐;echarts堆叠柱状图;echarts数据集dataset结构;

提示:主要解决三个问题:1.echarts双Y轴设置和对齐 2.echarts堆叠柱状图 3.echarts数据集dataset结构 一、echarts双Y轴设置和对齐 1.双Y轴: yAxis两组数据,且series有组数据设置 yAxisIndex: 1 代表使用哪个Y轴的数据展示&#…

算法训练Day37:738.单调递增的数字 968.监控二叉树

文章目录 单调递增的数字题解 监控二叉树题解 单调递增的数字 CategoryDifficultyLikesDislikesContestSlugProblemIndexScorealgorithmsMedium (50.32%)3690--0 Tags 贪心 | 数学 Companies 当且仅当每个相邻位数上的数字 x 和 y 满足 x < y 时&#xff0c;我们称这个…

【源码解析】多数据源 dynamic-datasource快速入门及源码解析

快速入门 依赖引入 <dependency><groupId>com.baomidou</groupId><artifactId>dynamic-datasource-spring-boot-starter</artifactId><version>3.5.1</version></dependency>配置文件 spring.datasource.druid.stat-view-se…

在不确定性时代,亚马逊云科技让企业拥有持续增长力

2023年3月29日「哈佛商业评论-未来管理沙龙」活动盛大启幕&#xff0c;此次沙龙活动以穿越周期的力量为主题方向&#xff0c;以解码跨国企业持续增长源动力为主旨&#xff0c;希望为企业高层管理者们带来更多思考和启迪。 作为特邀嘉宾&#xff0c;亚马逊全球副总裁、亚马逊云…

【数据库】数据库的基础知识

目录 前言 1、 查看数据库 1.1、查看所有数据库&#xff08;show databases;&#xff09; 1.2、创建数据库之后&#xff0c;查看创建的数据库的基本信息。 2、 创建数据库 2.1、直接创建数据库&#xff08;create database [数据库名];&#xff09; 2.2、创建数据库的时…

如何将b站缓存的m4s视频转换成mp4格式

阅读前请看一下&#xff1a;我是一个热衷于记录的人&#xff0c;每次写博客会反复研读&#xff0c;尽量不断提升博客质量。文章设置为仅粉丝可见&#xff0c;是因为写博客确实花了不少精力。希望互相进步谢谢&#xff01;&#xff01; 文章目录 阅读前请看一下&#xff1a;我是…

【Unity VR开发】结合VRTK4.0:瞬移

语录&#xff1a; 到不了的地方都叫做远方&#xff0c;回不去的世界都叫做家乡&#xff0c;我一直向往的却是比远更远的地方。 前言&#xff1a; 在VR场景中的移动主要有&#xff1a;瞬移和平移。瞬移相当于在虚拟世界中标记出目标位置&#xff0c;并自动传输到该位置&#xff…

【C++】5. 引用

文章目录 前言一、引用1.1 理解引用1.2 引用的特性1.3 引用的权限1.4 引用的使用场景1.4.1 做参数1.4.2 做返回值 1.5 引用的本质 前言 C语言中什么最难学&#xff1f;那当然就是指针了。不但使用起来麻烦&#xff0c;时不时还会产生一些意料之外的错误。C提供了一种方式&…

Direct local .aar file dependencies are not supported when building an AAR.

前言 起因&#xff1a;项目中含有视频播放功能&#xff0c;使用的是GSYVideoPlayer&#xff0c;因为公司网络问题经常依赖添加不了&#xff0c;所以将关于它的aar包全部下载下来直接本地依赖。 因为多个业务都可能涉及视频播放功能&#xff0c;为了复用&#xff0c;就想着将视频…

XTDrone PX4 仿真平台|使用Docker快速部署仿真环境

XTDrone PX4 仿真平台|使用Docker快速部署仿真环境 Docker简介NVIDIA驱动安装NVIDIA-Docker安装Docker镜像下载与使用Docker与宿主机建立ROS通信宿主机安装 XTDrone 源码 宿主机系统环境Ubuntu20.04 Docker简介 Docker 是一个开源的应用容器引擎&#xff0c;让开发者可以打包…

TestNG 中使用 Guice 来进行依赖注入

Guice是Google开发的一个轻量级&#xff0c;基于Java5&#xff08;主要运用泛型与注释特性&#xff09;的依赖注入框架(IOC)。 Guice非常小而且快。Guice是类型安全的&#xff0c;它能够对构造函数&#xff0c;属性&#xff0c;方法&#xff08;包含任意个参数的任意方法&…

3.微服务项目实战---Nacos Discovery--服务治理

3.1 服务治理介绍 先来思考一个问题 通过上一章的操作&#xff0c;我们已经可以实现微服务之间的调用。但是我们把服务提供者的网络地址 &#xff08; ip &#xff0c;端口&#xff09;等硬编码到了代码中&#xff0c;这种做法存在许多问题&#xff1a; 一旦服务提供者地址…

什么?Python一行命令快速搭建HTTP服务器并公网访问?

文章目录 1.前言2.本地http服务器搭建2.1.Python的安装和设置2.2.Python服务器设置和测试 3.cpolar的安装和注册3.1 Cpolar云端设置3.2 Cpolar本地设置 4.公网访问测试5.结语 转载自远程内网穿透的文章&#xff1a;【Python】快速简单搭建HTTP服务器并公网访问「cpolar内网穿透…

【C++入门必备知识:内联函数+指针空值nullptr】

【C入门必备知识&#xff1a;内联函数指针空值nullptr】 ①.内联函数Ⅰ.概念Ⅱ.宏与内联Ⅲ.总结 ②.指针空值nullptr(C11)Ⅰ.C98中的指针空值Ⅱ.注意&#xff1a; ①.内联函数 Ⅰ.概念 用inline修饰的函数就叫做内联函数&#xff0c;编译时C编译器会在调用内联函数的地方将函数…

密歇根大学,一个被低估的美国公立常春藤名校

密歇根大学&#xff08;University of Michigan&#xff09;创建于1817年&#xff0c;是美国历史最悠久的公立大学之一&#xff0c;被誉为“公立常春藤”和“公立大学的典范”&#xff0c;与加州大学伯克利分校和威斯康星大学麦迪逊分校等大学一起代表了美国公立大学的最高水平…

Unity Camera -- (1)概览

Camera章节笔记所用的资源包在这里&#xff1a; https://connect-prd-cdn.unity.com/20230208/a0898204-bc36-4d6e-a3b2-d4b83ae67c1d/CreativeCore_Camera_2021.3LTS.ziphttps://connect-prd-cdn.unity.com/20230208/a0898204-bc36-4d6e-a3b2-d4b83ae67c1d/CreativeCore_Came…

ERTEC200P-2 PROFINET设备完全开发手册(9-1)

9. PROFIDRIVE AC1/AC4参考代码 PROFIdrive是西门子 Profibus 与 Profinet 两种通讯方式针对驱动的生产与自动化控制应用的一种协议框架&#xff0c;也可以称作“行规”&#xff0c; PROFIdrive使得用户更快捷方便实现对驱动的控制。PROFIdrive的最大特点是互操作性 – 不同厂…

低代码平台名声臭,用起来却真香——60%开发者不敢承认

群体盲从意识会淹没个体的理性&#xff0c;个体一旦将自己归入该群体&#xff0c;其原本独立的理性就会被群体的无知疯狂所淹没。——《乌合之众》 不知道从什么时候开始&#xff0c;“低代码不行”的论调充斥着整个互联网圈子&#xff0c;csdn、掘金、知乎、B站、脉脉……到处…

遗传算法求取函数最值问题

目录 1. 关于遗传算法 2. 遗传算法的步骤 3. 代码实现 3.1 工具函数 3.1.1 目标函数 3.1.2 解码 3.1.3 交叉 3.1.4 变异 3.2 主函数部分 3.3 代码 4. 其他 1. 关于遗传算法 遗传算法是根据生物进化论提出的计算最优解的一种算法&#xff0c;核心思想是物竞天择&…