非常小的一个东西,Spring依赖注入Bean类型的8种情况
大家好,我是三友~~
今天来讲一个可能看似没有用但是实际又有点用的一个小东西,那就是@Autowired支持注入哪些Bean的类型。
为啥要讲这个呢?
故事说起来可能就比较长了。
不过长话可以短说,仅仅就是突然想起来之前有一个妹子问过我这个问题!
微信公众号:三友的java日记

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注解的循环依赖的场景,不了解的小伙伴可以看一下 @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提供的两接口

ObjectProvider继承了ObjectFactory

@Autowired也可以直接注入这两个接口。
@Autowired
private ObjectFactory<MessageNotifier> messageNotifierObjectFactory;
@Autowired
private ObjectProvider<MessageNotifier> messageNotifierObjectProvider;
代码如下:

从这段代码也可以看出,最终注入的其实是DependencyObjectProvider实现。
ObjectFactory也是用来做延迟注入的操作,跟@Lazy作用差不多,但是实现原理不一样。
用上面的例子来说,注入ObjectFactory的时候并有创建MessageNotifier对象。
当需要使用MessageNotifier的时候需要通过ObjectFactory的getObject方法获取,此时才会真正创建MessageNotifier对象。
MessageNotifier messageNotifier = messageNotifierObjectFactory.getObject();

所以@Async注解导致的循环依赖异常不仅可以通过@Lazy注解解决,也可以通过注入ObjectFactory的方式解决。
同理,ObjectProvider也有延迟加载的功能,但是除了延迟加载之外,ObjectProvider额外提供了跟Optional安全注入的功能,这个功能ObjectFactory是没有的。
上面的例子中,当使用ObjectFactory的getObject方法时,如果Spring容器中不存在MessageNotifier对象,此时也会抛NoSuchBeanDefinitionException异常。
但是ObjectProvider额外提供的getIfAvailable方法就支持获取不存在的对象的功能,当通过getIfAvailable获取的对象不存在时,只会返回null,并不会出抛异常。

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注入都是一样的。
往期热门文章推荐
扫码或者搜索关注公众号 三友的java日记 ,及时干货不错过,公众号致力于通过画图加上通俗易懂的语言讲解技术,让技术更加容易学习,回复 面试 即可获得一套面试真题。

非常小的一个东西,Spring依赖注入Bean类型的8种情况的更多相关文章
- Spring 依赖注入优化
Spring 依赖注入优化 原创: carl.zhao SpringForAll社区 今天 Spring 最大的好处就是依赖注入,关于什么是依赖注入,在Stack Overflow上面有一个问题,如何 ...
- Spring依赖注入(IOC)那些事
小菜使用Spring有几个月了,但是对于它的内部原理,却是一头雾水,这次借着工作中遇到的一个小问题,来总结一下Spring. Spring依赖注入的思想,就是把对象交由Spring容器管理,使用者只需 ...
- Spring学习笔记——Spring依赖注入原理分析
我们知道Spring的依赖注入有四种方式,各自是get/set方法注入.构造器注入.静态工厂方法注入.实例工厂方法注入 以下我们先分析下这几种注入方式 1.get/set方法注入 public cla ...
- Spring依赖注入三种方式详解
在讲解Spring依赖注入之前的准备工作: 下载包含Spring的工具jar包的压缩包 解压缩下载下来的Spring压缩包文件 解压缩之后我们会看到libs文件夹下有许多jar包,而我们只需要其中的c ...
- Spring依赖注入:注解注入总结
更多11 spring 依赖注入 注解 java 注解注入顾名思义就是通过注解来实现注入,Spring和注入相关的常见注解有Autowired.Resource.Qualifier.S ...
- Spring的依赖注入(DI)三种方式
Spring依赖注入(DI)的三种方式,分别为: 1. 接口注入 2. Setter方法注入 3. 构造方法注入 下面介绍一下这三种依赖注入在Spring中是怎么样实现的. 首先我们需要以下几个 ...
- Spring依赖注入 --- 简单使用说明
Spring依赖注入 --- 简单使用说明 本文将对spring依赖注入的使用做简单的说明,enjoy your time! 1.使用Spring提供的依赖注入 对spring依赖注入的实现方法感兴趣 ...
- Spring依赖注入 --- 模拟实现
Spring依赖注入 --- 模拟实现 面向接口编程,又称面向抽象编程, 数据库如果发生更改,对应的数据访问层也应该改变多写几个实现,需要用谁的时候在service里new谁就可以了面向抽象编程的好处 ...
- Java Web系列:Spring依赖注入基础
一.Spring简介 1.Spring简化Java开发 Spring Framework是一个应用框架,框架一般是半成品,我们在框架的基础上可以不用每个项目自己实现架构.基础设施和常用功能性组件,而是 ...
- spring依赖注入源码分析和mongodb自带连接本地mongodb服务逻辑分析
spring依赖注入本质是一个Map结构,key是beanId,value是bean对应的Object. autowired是怎么将定义的接口与对应的bean类建立联系? <bean name= ...
随机推荐
- Surface Pro (1796),安装Win11之后出现的问题。
2020年年中我为了体验微软新的操作系统,加入了Review计划,即:Windows预览体验计划.然后升级到了Win11.由于苏菲一直是作为辅助设备用,所以平时就是开节电模式,中途也升级了几次Win1 ...
- css 背景渐变
1.渐变从左到右 background: linear-gradient(to right,#000,#fff); 2.渐变从上到下 background: linear-gradient(tobot ...
- 操作系统|03.Linux基础(2)
Linux基础(二) 3.vim编辑器 命令模式:控制光标移动,对文本进行删除.复制.粘贴等工作.编辑模式:正常的文本录入.末行模式:保存.退出和设置编辑环境. 3.1命令模式常用命令 -r:恢复系统 ...
- vue中sso登录使用VueKeycloak登录
一,先下载vuekeycloakjs npm install @dsb-norge/vue-keycloak-js --save 二,引入 import VueKeycloakJs from '@ds ...
- python3中的负数整除、求余问题
注:小白问题,大神们请忽略先看示例,非整除: >>> -10/3-3.3333333333333335>>> 10/-3-3.3333333333333335> ...
- UI自动化之【chromedriver.exe无法删除问题】
想删掉chromedriver.exe,结果提示被打开 在任务管理器中,找到Chromedriver.exe,结束进程
- 第15章 授权:保护您的应用程序(ASP.NET Core in Action, 2nd Edition)
本章包括 使用授权控制谁可以使用你的应用 对策略使用基于声明的授权 创建自定义策略以处理复杂的需求 根据所访问的资源授权请求 隐藏用户未经授权访问的Razor模板中的元素 在第14章中,我向您展示了如 ...
- 如何卸载powermill?怎么把powermill彻底卸载删除干净重新安装的方法【转载】
如何卸载powermill?怎么把powermill彻底卸载删除干净重新安装的方法.powermill显示已安装或者报错出现提示安装未完成某些产品无法安装的问题,怎么完全彻底删除清理干净powermi ...
- Navicat15激活
1.下载Navicat for MySQL 15 https://www.navicat.com.cn/download/navicat-for-mysql 2.下载激活工具 注意:因某些限制,下载链 ...
- Java实现图片上传返回上传地址
**关于在实际开发中最常用也是用的最多的Java实现文档.图片上传.***一.准备阶段*文档.图片上传有几种方式,包括传统的ajax上传,云上传,这里给大家实现通过代码将图片上传至七牛云服务器并返回图 ...