明天来讲一个可能看似没有用然而理论又有点用的一个小东西,那就是@Autowired反对注入哪些Bean的类型。

为啥要讲这个呢?

故事说起来可能就比拟长了。

不过长话能够短说,仅仅就是忽然想起来之前有一个妹子问过我这个问题!

1、一般对象

这没什么好说的,大家都这么用的,比方须要用到UserService,间接@Autowired就能够了。

@Autowiredprivate UserService userService;

2、Collection及其子接口

除了反对注入一个繁多的对象之外,@Autowired还反对注入一个Collection对象。

比如说,当初有个音讯告诉的接口MessageNotifier

这种接口个别都会有不同的实现,比如说通过邮件告诉,或者app,短信等等,所以就有多种实现,此时如果须要注入MessageNotifier,就能够应用注入Collection的形式,比方

@Autowiredprivate List<MessageNotifier> messageNotifiers;

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

3、数组

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

@Autowiredprivate MessageNotifier[] messageNotifiers;

代码如下:

4、Map

同样的,@Autowired还能够注入一个Map。

@Autowiredprivate Map<String, MessageNotifier> messageNotifierMap;

此时注入的map,key的类型就是bean的名称,这种形式能够配合策略模式应用。

不过,这种形式只反对注入的是Map接口,不反对子类型接口,代码如下。

5、@Lazy

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

@Autowired@Lazyprivate 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类型。

@Autowiredprivate 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也能够间接注入这两个接口。

@Autowiredprivate ObjectFactory<MessageNotifier> messageNotifierObjectFactory;@Autowiredprivate 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注入都是一样的。