大家好,我是三友~~
创新互联建站坚持“要么做到,要么别承诺”的工作理念,服务领域包括:做网站、成都网站设计、企业官网、英文网站、手机端网站、网站推广等服务,满足客户于互联网时代的临安网站设计、移动媒体设计的需求,帮助企业找到有效的互联网解决方案。努力成为您成熟可靠的网络建设合作伙伴!
今天来讲的一个你可能不曾注意的小东西,那就是Spring依赖注入支持注入Bean的类型,这个小东西可能看似没有用但是实际又有点小用。
其实本来这周没打算写文章,但是突然之间就想到了之前有个妹子问过这个问题,并且网上这块东西说的也不多,所以就赶在周末的末尾匆匆写下了这篇文章。
这东西本身也没有什么复杂的原理,所以本文也并没有什么太多深入剖析源码的东西。
这没什么好说的,大家都这么用的,比如需要用到UserService,直接@Autowired就可以了。
@Autowired
private UserService userService;
除了支持注入一个单一的对象之外,@Autowired还支持注入一个Collection对象。
比如说,现在有个消息通知的接口MessageNotifier。
这种接口一般都会有不同的实现,比如说通过邮件通知,或者app,短信等等,所以就有多种实现,此时如果需要注入MessageNotifier,就可以使用注入Collection的方式,比如
@Autowired
private ListmessageNotifiers;
不过这种方式有个规定,那就是注入的类型必须是Collection及其子接口,如果你直接注入一个ArrayList,那么此时是不支持的。
同理,@Autowired可实现了注入一个数组的功能。
@Autowired
private MessageNotifier[] messageNotifiers;
代码如下:
同样的,@Autowired还可以注入一个Map。
@Autowired
private MapmessageNotifierMap;
此时注入的map,key的类型就是bean的名称,这种方式可以配合策略模式使用。
不过,这种方式只支持注入的是Map接口,不支持子类型接口,代码如下。
当一个注入的字段加了@Lazy注解之后,那么此时就代表这个字段是延迟注入。
@Autowired
@Lazy
private MessageNotifier messageNotifier;
延迟注入并不是不注入,而是注入目标对象类型的代理对象,真正的目标是当需要用到的时候在创建。
如图所示,当注入的MessageNotifier时加了@Lazy注解,那么此时注入的其实是MessageNotifier的代理对象,而真正的MessageNotifier对象并没有创建,图中代理对象我称为MessageNotifierProxy。
由于注入的是对象是代理对象MessageNotifierProxy,那么真正被使用的就是MessageNotifierProxy,一旦调用了MessageNotifierProxy的方法,此时MessageNotifierProxy会去Spring容器中查找真正的MessageNotifier对象,然后再调用MessageNotifier对象的方法。
代码如下:
这就是@Lazy延迟注入的原理。并不是不注入,而是注入一个代理对象,可以理解为一个占位符,一个空壳子,先占着位置,等用到这个壳子的时候,这个壳子会去查找到真正的对象,调用真正对象的方法。
@Lazy的一个使用场景就是用来解决Spring无法处理的循环依赖场景,比如使用了@Async注解的循环依赖的场景,不了解的小伙伴可以看一下 @Async注解的坑,小心 这篇文章
Optional是JDK1.8提供的一个api,可以优雅的解决判空的问题。
@Autowired也支持了注入Optional类型。
@Autowired
private OptionalmessageNotifier;
代码如下:
注入Optional这种方式可以解决注入的对象不存在的导致异常问题,也就是安全注入。
比如说,MessageNotifier这个对象Spring容器中并没有,如果直接注入,此时会抛NoSuchBeanDefinitionException异常
而直接通过注入Optional的方式就可以解决这个问题。
除了通过Optional的方式之外,也可以直接把@Autowired的required的属性设置为false来解决注入对象不存在的问题。
那Optional存在的作用是啥?
其实Optional的作用仅仅是不用写为空的判断,这也是Optional这个类的作用作用,除了这个,跟直接@Autowired对象并没有其它区别。
注入Optional这种方式其实用的不多,在我的映像中,我在源码中几乎没有看见这种注入方式。
ObjectFactory和ObjectProvider是Spring提供的两接口
ObjectFactory
ObjectProvider继承了ObjectFactory
ObjectProvider
@Autowired也可以直接注入这两个接口。
@Autowired
private ObjectFactorymessageNotifierObjectFactory;
@Autowired
private ObjectProvidermessageNotifierObjectProvider;
代码如下:
从这段代码也可以看出,最终注入的其实是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就使用这些,没有也不会报错。
首先,来讲一下什么是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这个接口,需要引入依赖
javax.inject
javax.inject
1
Spring也支持注入这个类型的接口
这个接口的功能跟前面提到的ObjectFactory功能是一样的,也支持延迟注入的功能。
到这Spring能够注入的Bean的8种类型就讲完了,其实这8种类型可以分为以下几种功能:
这几种方式并不是互斥的,比如说延迟注入也可以注入的是一个集合,前面举的MyBaisPlus自动装配时ObjectProvider的使用就是很好的例子。
同时虽然本文举例的是@Autowird注解和字段注入的方式,但上面提到的注入的Bean类型跟使用注解和注入方式没什么关系,@Resource注解,构造器注入,setter注入都是一样的。
分享文章:一个你可能不曾注意的小东西,Spring依赖注入Bean类型的八种情况
转载来于:http://www.mswzjz.com/qtweb/news2/200152.html
网站建设、网络推广公司-创新互联,是专注品牌与效果的网站制作,网络营销seo公司;服务项目有等
声明:本网站发布的内容(图片、视频和文字)以用户投稿、用户转载内容为主,如果涉及侵权请尽快告知,我们将会在第一时间删除。文章观点不代表本网站立场,如需处理请联系客服。电话:028-86922220;邮箱:631063699@qq.com。内容未经允许不得转载,或转载时需注明来源: 创新互联