首页 > 其他分享 >非常小的一个东西,Spring依赖注入Bean类型的8种情况

非常小的一个东西,Spring依赖注入Bean类型的8种情况

时间:2023-03-27 13:24:06浏览次数:51  
标签:依赖 Spring ObjectFactory Bean MessageNotifier Optional ObjectProvider 注入

大家好,我是三友~~

今天来讲一个可能看似没有用但是实际又有点用的一个小东西,那就是@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提供的两接口

ObjectFactory
ObjectFactory

ObjectProvider继承了ObjectFactory

ObjectProvider
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,并不会出抛异常。

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注入都是一样的。

往期热门文章推荐

为什么RocketMQ会重复消费,我扒出了7种原因

如何去阅读源码,我总结了18条心法

如何实现延迟任务,我总结了11种方法

如何写出漂亮代码,我总结了45个小技巧

三万字盘点Spring/Boot的那些常用扩展点

两万字盘点那些被玩烂了的设计模式

扫码或者搜索关注公众号 三友的java日记 ,及时干货不错过,公众号致力于通过画图加上通俗易懂的语言讲解技术,让技术更加容易学习,回复 面试 即可获得一套面试真题。

标签:依赖,Spring,ObjectFactory,Bean,MessageNotifier,Optional,ObjectProvider,注入
From: https://www.cnblogs.com/zzyang/p/17261200.html

相关文章

  • flink1.16连接hive2.3.9依赖报错
    Causedby:java.lang.ClassNotFoundException:org.apache.flink.table.gateway.api.endpoint.SqlGatewayEndpointFactory原来的导包依赖是:<groupId>org.apache.flink</gr......
  • 某大厂面试题:说一说Java、Spring、Dubbo三者SPI机制的原理和区别
    大家好,我是三友~~今天来跟大家聊一聊Java、Spring、Dubbo三者SPI机制的原理和区别。其实我之前写过一篇类似的文章,但是这篇文章主要是剖析dubbo的SPI机制的源码,中间只是......
  • Go语言:一文看懂什么是DI依赖注入(dependency injection)设计模式
    前言:本文主要介绍的是Goalng中关于DI的部分,前一部分会先通过典型的面向对象语言Java引入DI这个概念仅供初学者理解使用,文章如有纰漏敬请指出本文涉及到的知识面较为......
  • Spring源码核心剖析
    作者:京东科技韩国凯前言SpringAOP作为Spring最核心的能力之一,其重要性不言而喻。然后需要知道的是AOP并不只是Spring特有的功能,而是一种思想,一种通用的功能。而SpringAOP只......
  • SpringBoot 集成微信支付的各种支付产品
    SpringBoot是一款非常流行的Java开发框架,而微信支付则是众多移动支付产品中的佼佼者,整合两者可以让我们更方便地开发各种支付产品。在本篇博客中,我将介绍如何在Spring......
  • 房产中介管理软件第13课:使用AutoFac做依赖注入处理
    使用了AutoFac做依赖注入的处理一、nuget加载AutoFac二、Program.cs中注入代码#regionAutofac自动注册builder.Host.UseServiceProviderFactory(newAutofacServic......
  • 依赖注入之IConfiguration
    publicclassStartup{publicStartup(IConfigurationconfiguration){Configuration=configuration;}pu......
  • Spring源码核心剖析
    作者:京东科技韩国凯前言SpringAOP作为Spring最核心的能力之一,其重要性不言而喻。然后需要知道的是AOP并不只是Spring特有的功能,而是一种思想,一种通用的功能。而SpringAO......
  • SpringBoot Windows 自启动 - 通过 Windows Service 服务实现
    SpringBoot在Windows运行时,有个黑窗体,容易被不小心选中或关闭,或者服务器重启后,不能自动运行,注册为WindowsService服务可实现SpringBoot项目在Windows中随系统自启动......
  • SpringBoot(六)
    5.2任务这里说的任务系统指的是定时任务。定时任务是企业级开发中必不可少的组成部分,如长周期业务数据的计算,如年度报表,如系统脏数据的处理,再比如系统性能监控报告,还有抢......