最近依旧在学习阅读 Spring Boot 的源代码, 在此过程中涉及到很多在日常项目中比较少见的功能特性, 对此深入研究一下, 也挺有意思, 这也是阅读源码的魅力之一. 这里写成文章, 分享给大家.
自动配置中的 ObjectProvider
在阅读 Spring Boot 自动配置源码中关于 Tomcat 的配置时, 看到这样如下的自动配置配置源代码.
- @Configuration(proxyBeanMethods = false)
- @ConditionalOnClass({Servlet.class,Tomcat.class, UpgradeProtocol.class })
- @ConditionalOnMissingBean(value = ServletwebServerFactory.class, search = SearchStrategy.CURRENT)
- public static class EmbeddedTomcat {
- @Bean
- public TomcatServletWebServerFactory tomcatServletWebServerFactory(
- ObjectProvider<TomcatConnectorCustomizer> connectorCustomizers,
- ObjectProvider<TomcatContextCustomizer> contextCustomizers,
- ObjectProvider<TomcatProtocolHandlerCustomizer<?>> protocolHandlerCustomizers) {
- // ...
- }
- }
这就是一个常规的基于 Java 的配置类, 那么你是否发现它在用法与其他的有所不同? 是的, 那就是三个 ObjectProvider 的参数. 这也是本文要讲的内容.
Spring 的注入
在介绍 ObjectProvider 的使用之前, 我们先来回顾一下注入相关的知识.
在 Spring 的使用过程中, 我们可以通过多种形式将一个类注入到另外一个类当中, 比如通过 @Autowired 和 @Resources 注解.
而 @Autowired 又可以注解在不同的地方来达到注入的效果, 比如注解在构造函数上:
- @Service
- public class FooService {
- private final FooRepository repository;
- @Autowired
- public FooService(FooRepository repository) {
- this.repository = repository
- }
- }
注解在属性上:
- @Service
- public class FooService {
- @Autowired
- private final FooRepository repository;
- }
注解在 setter 方法上:
- @Service
- public class FooService {
- private final FooRepository repository;
- @Autowired
- public void setFooRepository(FooRepository repository) {
- this.repository = repository
- }
- }
spring4.3 新特性
上面是最常见的注入方式, 如果忘记写 @Autowired 注解, 那么在启动的时候就会抛出异常.
但在 spring 4.3 之后, 引入了一个新特性: 当构造方法的参数为单个构造参数时, 可以不使用 @Autowired 进行注解.
因此, 上面的代码可变为如下形式:
- @Service
- public class FooService {
- private final FooRepository repository;
- public FooService(FooRepository repository) {
- this.repository = repository
- }
- }
使用此种形式便会显得优雅一些. 该特性, 在 Spring Boot 的自动配置类中大量被使用.
依赖关系的改进
同样是在 Spring 4.3 版本中, 不仅隐式的注入了单构造参数的属性. 还引入了 ObjectProvider 接口.
ObjectProvider 接口是 ObjectFactory 接口的扩展, 专门为注入点设计的, 可以让注入变得更加宽松和更具有可选项.
那么什么时候使用 ObjectProvider 接口?
如果待注入参数的 Bean 为空或有多个时, 便是 ObjectProvider 发挥作用的时候了.
如果注入实例为空时, 使用 ObjectProvider 则避免了强依赖导致的依赖对象不存在异常; 如果有多个实例, ObjectProvider 的方法会根据 Bean 实现的 Ordered 接口或 @Order 注解指定的先后顺序获取一个 Bean. 从而了提供了一个更加宽松的依赖注入方式.
Spring 5.1 之后提供了基于 Stream 的 orderedStream 方法来获取有序的 Stream 的方法.
使用 ObjectProvider 之后, 上面的代码便变为如下方式:
- @Service
- public class FooService {
- private final FooRepository repository;
- public FooService(ObjectProvider<FooRepository> repositoryProvider) {
- this.repository = repositoryProvider.getIfUnique();
- }
- }
这样的好处很显然, 当容器中不存在 FooRepository 或存在多个时, 可以从容处理. 但坏处也很明显, 如果 FooRepository 不能为 null, 则可能将异常从启动阶段转移到业务运行阶段.
ObjectProvider 源码
ObjectProvider 的源码及解析如下:
- public interface ObjectProvider<T> extends ObjectFactory<T>, Iterable<T> {
- // 返回指定类型的 bean, 如果容器中不存在, 抛出 NoSuchBeanDefinitionException 异常
- // 如果容器中有多个此类型的 bean, 抛出 NoUniqueBeanDefinitionException 异常
- T getObject(Object... args) throws BeansException;
- // 如果指定类型的 bean 注册到容器中, 返回 bean 实例, 否则返回 null
- @Nullable
- T getIfAvailable() throws BeansException;
- // 如果返回对象不存在, 则进行回调, 回调对象由 Supplier 传入
- default T getIfAvailable(Supplier<T> defaultSupplier) throws BeansException {
- T dependency = getIfAvailable();
- return (dependency != null ? dependency : defaultSupplier.get());
- }
- // 消费对象的一个实例(可能是共享的或独立的), 如果存在通过 Consumer 回调消耗目标对象.
- default void ifAvailable(Consumer<T> dependencyConsumer) throws BeansException {
- T dependency = getIfAvailable();
- if (dependency != null) {
- dependencyConsumer.accept(dependency);
- }
- }
- // 如果不可用或不唯一 (没有指定 primary) 则返回 null. 否则, 返回对象.
- @Nullable
- T getIfUnique() throws BeansException;
- // 如果存在唯一对象, 则调用 Supplier 的回调函数
- default T getIfUnique(Supplier<T> defaultSupplier) throws BeansException {
- T dependency = getIfUnique();
- return (dependency != null ? dependency : defaultSupplier.get());
- }
- // 如果存在唯一对象, 则消耗掉该对象
- default void ifUnique(Consumer<T> dependencyConsumer) throws BeansException {
- T dependency = getIfUnique();
- if (dependency != null) {
- dependencyConsumer.accept(dependency);
- }
- }
- // 返回符合条件的对象的 Iterator, 没有特殊顺序保证(一般为注册顺序)
- @Override
- default Iterator<T> iterator() {
- return stream().iterator();
- }
- // 返回符合条件对象的连续的 Stream, 没有特殊顺序保证(一般为注册顺序)
- default Stream<T> stream() {
- throw new UnsupportedOperationException("Multi element access not supported");
- }
- // 返回符合条件对象的连续的 Stream. 在标注 Spring 应用上下文中采用 @Order 注解或实现 Order 接口的顺序
- default Stream<T> orderedStream() {
- throw new UnsupportedOperationException("Ordered element access not supported");
- }
- }
其中, 在 BeanFactory 中也使用了该接口来定义方法的返回值:
- public interface BeanFactory {
- <T> ObjectProvider<T> getBeanProvider(Class<T> requiredType);
- <T> ObjectProvider<T> getBeanProvider(ResolvableType requiredType);
- ...
- }
至此, 关于 ObjectProvider 的使用和源码解析完成.
来源: https://www.cnblogs.com/secbro/p/11974729.html