今天讲一个看似没用但其实很有用的小东西,就是@Autowired支持注入哪些类型的bean。你为什么要说这个?故事可能会更长。不过话又说回来了,我突然想起以前有个女生问过我这个问题!1、普通的对象没什么好说的。每个人都这样使用它。比如需要使用UserService,直接@Autowired即可。@Autowiredprivate用户服务用户服务;2、@Autowired除了支持单个对象、Collection及其子接口的注入外,还支持Collection对象的注入。比如现在有一个消息通知的接口MessageNotifier。这种接口一般都有不同的实现,比如邮件通知,或者app,短信等,所以实现有很多种。这时候如果需要注入MessageNotifier,可以使用注入Collection的方法,比如@AutowiredprivateListmessageNotifiers;但是这个方法有一个规则,就是注入的类型必须是Collection及其子接口。如果直接注入ArrayList,暂时不支持。3.同样对于数组,@Autowired可以实现注入数组的功能。@AutowiredprivateMessageNotifier[]messageNotifiers;代码如下:4.Map同样,@Autowired也可以注入一个Map。@AutowiredprivateMapmessageNotifierMap;此时注入的map和key的type就是bean的名字,可以配合strategy模式使用。但是该方法只支持Map接口的注入,不支持subtype接口。代码如下。5.@Lazy当一个注入的字段被@Lazy注解时,表示该字段是延迟注入的。@Autowired@LazyprivateMessageNotifiermessageNotifier;延迟注入不是不注入,而是注入到目标对象类型的代理对象中。真正的目标是在需要时创建它。如图所示,当注入的MessageNotifier加上@Lazy注解后,那么此时实际上注入的是MessageNotifier的代理对象,并没有创建真正的MessageNotifier对象。图中的代理对象叫做MessageNotifierProxy。由于注入的对象是代理对象MessageNotifierProxy,那么实际使用的是MessageNotifierProxy。一旦调用了MessageNotifierProxy的方法,MessageNotifierProxy就会去Spring容器中寻找真正的MessageNotifier对象,然后调用MessageNotifier对象的方法。代码如下:这就是@Lazy延迟注入的原理。不是不注入,而是注入一个代理对象,可以理解为一个占位符,一个空壳,先占位置,在使用壳的时候,壳会找到真正的对象,并调用该对象的方法实物。@Lazy的一个使用场景是解决Spring无法处理的循环依赖场景,比如使用@Async注解的循环依赖场景6.OptionalOptional是JDK1.8提供的一个API,可以优雅的解决空判断问题.@Autowired还支持注入Optional类型。@AutowiredprivateOptionalmessageNotifier;代码如下:注入Optional可以解决注入对象不存在导致异常的问题,即安全注入。例如,Spring容器中不存在MessageNotifier对象。如果直接注入的话,这时候会抛出NoSuchBeanDefinitionException,直接注入Optional就可以解决这个问题。除了Optional方法,也可以直接将@Autowired的required属性设置为false,解决注入对象不存在的问题。Optional的存在有什么作用?其实Optional的作用只是判断不需要为空,这也是Optional类的作用。除此之外,与直接@Autowired对象没有其他区别。注入Optional不是很实用。在我的印象中,我几乎看不到源代码中的这种注入。7、ObjectFactory和ObjectProviderObjectFactory和ObjectProvider是Spring提供的两个接口。ObjectProvider继承了ObjectFactory@Autowired,可以直接注入这两个接口。@AutowiredprivateObjectFactorymessageNotifierObjectFactory;@AutowiredprivateObjectProvidermessageNotifierObjectProvider;代码如下:从这段代码也可以看出,最后注入的其实是DependencyObjectProvider的实现。ObjectFactory也用于延迟注入,与@Lazy类似,但实现原理不同。使用上面的示例,在注入ObjectFactory时不会创建MessageNotifier对象。当需要使用MessageNotifier时,需要通过ObjectFactory的getObject方法获取,然后才会真正创建MessageNotifier对象。MessageNotifiermessageNotifier=messageNotifierObjectFactory.getObject();所以@Async注解导致的循环依赖异常不仅可以通过@Lazy注解解决,也可以通过注入ObjectFactory来解决。同样,ObjectProvider也有懒加载的功能,但是除了懒加载之外,ObjectProvider还额外提供了可选安全注入的功能,这是ObjectFactory所没有的。上面的例子中,在使用ObjectFactory的getObject方法时,如果Spring容器中不存在MessageNotifier对象,也会抛出NoSuchBeanDefinitionException。但是ObjectProvider提供的getIfAvailable方法支持获取不存在对象的功能。当通过getIfAvailable获取的对象不存在时,只会返回null,不会抛出异常。ObjectFactory和ObjectProvider在框架内部被大量使用。比如MybatisPlus在自动组装的时候,大量使用了ObjectProvider,泛型类型是数组或者集合,就对应了上面说的。这样才能安全注射。当Spring容器有这些对象时,MybatisPlus会使用它们,不会报错。8.JSR-330Provider首先说说什么是JSR-330。JSR是JavaSpecificationRequests的缩写,是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.injectjavax.inject1Spring也支持注入这种类型的接口。这个接口的作用和上面提到的ObjectFactory函数是一样的,同样支持延迟注入的功能。综上所述,Spring可以注入的8种bean就说完了。这8种类型其实可以分为以下功能:单次注入,就是注入单个对象集合注入,可以注入数组或者集合进行延迟注入,比如@Lazy,ObjectFactory,ObjectProvider,JSR-330Provider安全注入是不存在的,不会抛出异常,比如Optional和ObjectProvider是不互斥的。比如延迟注入也可以注入到一个集合中,上面提到的MyBaisPlus自动组装时ObjectProvider的使用就是一个很好的例子。同时,虽然本文举例说明了@Autowird注解和字段注入方式,但是上面提到的注入的Bean类型与注解和注入方式无关。@Resource注解、构造器注入、setter注入都是一样的。