一个你可能不曾注意的小东西,Spring依赖注入Bean类型的8种情况

今天来讲的一个你可能不曾注意的小东西,那就是Spring依赖注入支持注入Bean的类型,这个小东西可能看似没有用但是实际又有点小用。

其实本来这周没打算写文章,但是突然之间就想到了之前有个妹子问过这个问题,并且网上这块东西说的也不多,所以就赶在周末的末尾匆匆写下了这篇文章。

这东西本身也没有什么复杂的原理,所以本文也并没有什么太多深入剖析源码的东西。

图片

1、普通对象

这没什么好说的,大家都这么用的,比如需要用到UserService,直接@Autowired就可以了。

@Autowired
private UserService userService;
2、Collection及其子接口

除了支持注入一个单一的对象之外,@Autowired还支持注入一个Collection对象。

比如说,现在有个消息通知的接口MessageNotifier

这种接口一般都会有不同的实现,比如说通过邮件通知,或者app,短信等等,所以就有多种实现,此时如果需要注入MessageNotifier,就可以使用注入Collection的方式,比如

@Autowired
private List<MessageNotifier> messageNotifiers;

不过这种方式有个规定,那就是注入的类型必须是Collection及其子接口,如果你直接注入一个ArrayList,那么此时是不支持的。

图片

3、数组

同理,@Autowired可实现了注入一个数组的功能。

@Autowired
private MessageNotifier[] messageNotifiers;

代码如下:

图片

4、Map

同样的,@Autowired还可以注入一个Map。

@Autowired
private Map<String, MessageNotifier> messageNotifierMap;

此时注入的map,key的类型就是bean的名称,这种方式可以配合策略模式使用。

不过,这种方式只支持注入的是Map接口,不支持子类型接口,代码如下。

图片

5、@Lazy

当一个注入的字段加了@Lazy注解之后,那么此时就代表这个字段是延迟注入。

@Autowired
@Lazy
private MessageNotifier messageNotifier;

延迟注入并不是不注入,而是注入目标对象类型的代理对象,真正的目标是当需要用到的时候在创建。

图片

如图所示,当注入的MessageNotifier时加了@Lazy注解,那么此时注入的其实是MessageNotifier的代理对象,而真正的MessageNotifier对象并没有创建,图中代理对象我称为MessageNotifierProxy

由于注入的是对象是代理对象MessageNotifierProxy,那么真正被使用的就是MessageNotifierProxy,一旦调用了MessageNotifierProxy的方法,此时MessageNotifierProxy会去Spring容器中查找真正的MessageNotifier对象,然后再调用MessageNotifier对象的方法。

代码如下:

图片

这就是@Lazy延迟注入的原理。并不是不注入,而是注入一个代理对象,可以理解为一个占位符,一个空壳子,先占着位置,等用到这个壳子的时候,这个壳子会去查找到真正的对象,调用真正对象的方法。

@Lazy的一个使用场景就是用来解决Spring无法处理的循环依赖场景,比如使用了@Async注解的循环依赖的场景。

6、Optional

Optional是JDK1.8提供的一个api,可以优雅的解决判空的问题。

@Autowired也支持了注入Optional类型。

@Autowired
private Optional<MessageNotifier> messageNotifier;

代码如下:

图片

注入Optional这种方式可以解决注入的对象不存在的导致异常问题,也就是安全注入。

比如说,MessageNotifier这个对象Spring容器中并没有,如果直接注入,此时会抛NoSuchBeanDefinitionException异常

图片

而直接通过注入Optional的方式就可以解决这个问题。

除了通过Optional的方式之外,也可以直接把@Autowired的required的属性设置为false来解决注入对象不存在的问题。

那Optional存在的作用是啥?

其实Optional的作用仅仅是不用写为空的判断,这也是Optional这个类的作用作用,除了这个,跟直接@Autowired对象并没有其它区别。

注入Optional这种方式其实用的不多,在我的映像中,我在源码中几乎没有看见这种注入方式。

7、ObjectFactory和ObjectProvider

ObjectFactory和ObjectProvider是Spring提供的两接口

图片

ObjectFactory

ObjectProvider继承了ObjectFactory

图片

ObjectProvider

@Autowired也可以直接注入这两个接口。

@Autowired
private ObjectFactory<MessageNotifier> messageNotifierObjectFactory;@Autowired
private ObjectProvider<MessageNotifier> messageNotifierObjectProvider;

代码如下:

图片

从这段代码也可以看出,最终注入的其实是DependencyObjectProvider实现。

ObjectFactory也是用来做延迟注入的操作,跟@Lazy作用差不多,但是实现原理不一样。

用上面的例子来说,注入ObjectFactory的时候并有创建MessageNotifier对象。

当需要使用MessageNotifier的时候需要通过ObjectFactory的getObject方法获取,此时才会真正创建MessageNotifier对象。

MessageNotifier messageNotifier = messageNotifierObjectFactory.getObject();

getObject实现如下

图片

getObject

所以@Async注解导致的循环依赖异常不仅可以通过@Lazy注解解决,也可以通过注入ObjectFactory的方式解决。

同理,ObjectProvider也有延迟注入的功能,但是除了延迟注入之外,ObjectProvider额外提供了跟Optional安全注入的功能,这个功能ObjectFactory是没有的。

上面的例子中,当使用ObjectFactory的getObject方法时,如果Spring容器中不存在MessageNotifier对象,此时也会抛NoSuchBeanDefinitionException异常。

但是ObjectProvider额外提供的getIfAvailable方法就支持获取不存在的对象的功能,当通过getIfAvailable获取的对象不存在时,只会返回null,并不会出抛异常。

图片

getIfAvailable方法

对比一下与getObject方法的实现,就是在获取对象的时候是否要求对象获取的对象不是必须的,这样获取不到就不会抛异常了。

ObjectFactory和ObjectProvider在框架内部中使用的还是比较多的。

就比如说,在MybatisPlus自动装配的时候就大量使用ObjectProvider

图片

并且泛型类型就是数组或者是集合,跟前面说的都对应上了。

通过这种方式就可以安全的注入,当Spring容器有这些对象的时候MybatisPlus就使用这些,没有也不会报错。

8、JSR-330 Provider

首先,来讲一下什么是JSR-330。

JSR是Java Specification Requests的缩写,是一种Java标准规范。

而330算是一个版本,除了330,听到的比较多的还有250。

这个规范定义了一些IOC的注解,我们熟知的比如@Resource、@PostConstruct、@PreDestroy注解都是JSR-250中提出的。

一些IOC的框架会基于这个标准来实现这些接口的功能,比如Spring、Dagger2等IOC框架都实现了这些注解的功能。

所以,如果你不使用Spring框架,使用其它的IOC框架,那么@Resource、@PostConstruct、@PreDestroy注解都是可以生效的。

在JSR-330中,提出了javax.inject.Provider这个接口

图片

不过,想使用JSR-330这个接口,需要引入依赖

<dependency><groupId>javax.inject</groupId><artifactId>javax.inject</artifactId><version>1</version>
</dependency>

Spring也支持注入这个类型的接口

图片

这个接口的功能跟前面提到的ObjectFactory功能是一样的,也支持延迟注入的功能。

总结

到这Spring能够注入的Bean的8种类型就讲完了,其实这8种类型可以分为以下几种功能:

  • 单一注入,就是注入一个单一的对象

  • 集合注入,可以注入数组或者集合

  • 延迟注入,比如@Lazy、ObjectFactory、ObjectProvider、JSR-330 Provider

  • 安全注入,不存在不会抛异常,比如Optional、ObjectProvider

这几种方式并不是互斥的,比如说延迟注入也可以注入的是一个集合,前面举的MyBaisPlus自动装配时ObjectProvider的使用就是很好的例子。

同时虽然本文举例的是@Autowird注解和字段注入的方式,但上面提到的注入的Bean类型跟使用注解和注入方式没什么关系,@Resource注解,构造器注入,setter注入都是一样的。

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Python学习笔记-Flask实现简单的抽奖程序

1.导入flask包和randint包 from flask import Flask,render_template from random import randint 2.初始化 Flask 应用: app Flask(__name__) 3. 定义英雄列表 hero [黑暗之女,狂战士,正义巨像,卡牌大师,德邦总管,无畏战车,诡术妖姬,猩红收割者,远古恐惧,正义天使,无极剑…

字节总部大楼私照流出,做他们的员工需要多牛!

在大厂上班究竟有多香&#xff1f; 大厂的工作环境&#xff0c;只有你想不到的硬核&#xff0c;没有它做不到的。 前段时间&#xff0c;字节跳动在北京办公室的一组私照在网上刷屏&#xff0c;看完我只有一个表情—— 抛开薪资和大厂光环不谈&#xff0c;就冲它的工作环境&…

算法---双指针练习-3(快乐数)

题目 1. 题目解析2. 讲解算法原理鸽巢原理 3. 编写代码 1. 题目解析 题目地址&#xff1a;点这里 2. 讲解算法原理 本题根据鸽巢原理是一定会有环的&#xff0c;最后要么无限循环1&#xff0c;要么碰到一个不为1的重复数继续循环 鸽巢原理 鸽巢原理&#xff08;Pigeonhole P…

C#与python交互(flask发送Get/Post请求)

先运行python&#xff0c;再运行C# **ps: 注意修改端口号**python发送Get/Post请求 # -*- coding: utf-8 -*- # Time : 2024/1/25 15:52 # Author : YY # File : post_test.py # Content&#xff1a;提交数据给客户端 from flask import Flask, request, jsonify, redirect…

【嵌入式——QT】标准对话框

【嵌入式——QT】标准对话框 文件对话框颜色对话框字体对话框输入对话框消息框代码示例 文件对话框 QFileDialog 常用静态函数 getOpenFileName&#xff1a;选择打开一个文件&#xff1b;getOpenFileNames&#xff1a;选择打开多个文件&#xff1b;getSaveFileName&#xff1…

WPF 消息提示 类似toast方式

WPF里面的消息提示一般都是MessageBox.Show()&#xff0c;这种样式不是很好看&#xff0c;所以就想办法重新搞了一个类似弹出消息的功能。原理很简单&#xff0c;就是弹出一个新窗体&#xff0c;然后等几秒窗体自动关闭。 先上效果图&#xff1a; 新建一个MsgHelper.cs类&…

Linux运维工程师不可或缺的10款工具

运维工程师在日常工作中频繁运用的10款工具&#xff0c;并细致阐述每款工具的功能、适用场景以及其卓越之处。 1. Shell脚本&#xff1a; 功能&#xff1a;主要用于自动化任务和批处理作业。 适用场景&#xff1a;频繁用于文件处理、系统管理、简单的网络管理等操作。 优势&…

重生奇迹mu战士大师技能加点怎么加

1、在重生奇迹MU中&#xff0c;战士大师的技能加点需要根据个人的游戏风格和需求来决定。一般来说&#xff0c;战士大师可以优先加点力量和体力&#xff0c;以增加攻击和生存能力。同时&#xff0c;可以适当加点敏捷来提高闪避和命中率。 2、在技能方面&#xff0c;可以根据个人…

云计算项目九:K8S安装

K8S安装 Kube-master安装 按照如下配置准备云主机 防火墙相关配置&#xff1a;禁用selinux&#xff0c;禁用swap&#xff0c;且在firewalld-*。上传kubernetes.zip 到跳板机 配置yum仓库&#xff08;跳板机&#xff09; 跳板机主机配置k8s软件源服务端 [rootjs ~]# yum -y…

5G工业网关是什么?

随着科技的飞速发展&#xff0c;5G技术已经逐渐渗透到我们生活的方方面面。而在工业领域&#xff0c;5G工业网关作为连接工业设备与网络的关键组件&#xff0c;正发挥着越来越重要的作用。HiWoo Box其5G工业网关产品以其卓越的性能和稳定性&#xff0c;正助力企业实现数字化转型…

考研数学|到底要不要做张宇《1000题》

根据你自身能力来选择真正适合你的题集&#xff0c;最后的做题效果会加倍。&#x1f60e; 我先分析一下张宇1000题集的特点&#xff0c;张宇1000更适合基础不错&#xff0c;想冲刺高分的同学。 1000分为强化和提高&#xff0c;是没有基础部分的&#xff0c;着重考察数学概念和技…

@大学生必看内容!QT创建C++项目,并使用Opencv进行图像处理!

一、创建C项目 二、向C项目部署opencv。详细步骤&#xff1a;查看地址。 避坑&#xff01;&#xff01;