• 【Spring源码三千问】@Lazy的替代者ObjectFactory 和 ObjectProvider


    前言

    @Lazy 可以解决某些特殊场景下的循环依赖问题。
    在翻阅 @Lazy 的源码注释时,得知 @Lazy 可以通过 ObjectFactory 和 ObjectProvider 来进行替代。
    下面我们就来看看 ObjectFactory 和 ObjectProvider 的原理和使用吧…

    @Lazy 相关的知识:
    @Lazy为什么可以解决特殊的循环依赖问题
    @Lazy延迟加载与延迟注入有什么区别

    Spring 版本

    Spring 5.3.9 (通过 SpringBoot 2.5.3 间接引入的依赖)

    正文

    ObjectProvider 作用分析

    ObjectProvider 的类图如下:
    ObjectProvider

    ObjectProvider 提供的是通过 ObjectProvider#getObject() 或者 ObjectProvider#getIfAvailable() 获取 Object (即: bean) 的能力。
    也就是说,在依赖注入时,注入的是一个 ObjectProvider 对象,想要获取到真正的 bean 时,可以通过调用 ObjectProvider#getObject() 或者 ObjectProvider#getIfAvailable()
    所以,它跟 @Lazy 起到的作用是很相似的。

    Spring 对 ObjectProvider 依赖的处理

    Spring 在 populateBean 时,会处理依赖属性的注入,最终会调用 DefaultListableBeanFactory#resolveDependency() 来对依赖进行解析。
    相关的源码如下:
    resolveDependency2

    可以看到,如果是 ObjectFactory 和 ObjectProvider 类型的依赖,那么会直接 return new DependencyObjectProvider(descriptor, requestingBeanName);,而不会触发依赖 bean 的加载。
    等到真正使用 ObjectProvider#getObject() 获取 bean 的时候,才会触发 bean 的加载。

    ObjectProvider 的使用场景

    ObjectProvider 大量出现在 SpringBoot 的 Configuration 配置类中,做为构造函数的入参来进行使用,即构造注入依赖。

    例如 MybatisPlus 中有如下代码:

    public MybatisPlusAutoConfiguration(MybatisPlusProperties properties,
                                        ObjectProvider<Interceptor[]> interceptorsProvider,
                                        ObjectProvider<TypeHandler[]> typeHandlersProvider,
                                        ObjectProvider<LanguageDriver[]> languageDriversProvider,
                                        ResourceLoader resourceLoader,
                                        ObjectProvider<DatabaseIdProvider> databaseIdProvider,
                                        ObjectProvider<List<ConfigurationCustomizer>> configurationCustomizersProvider,
                                        ObjectProvider<List<MybatisPlusPropertiesCustomizer>> mybatisPlusPropertiesCustomizerProvider,
                                        ApplicationContext applicationContext) {
        this.properties = properties;
        this.interceptors = interceptorsProvider.getIfAvailable();
        this.typeHandlers = typeHandlersProvider.getIfAvailable();
        this.languageDrivers = languageDriversProvider.getIfAvailable();
        this.resourceLoader = resourceLoader;
        this.databaseIdProvider = databaseIdProvider.getIfAvailable();
        this.configurationCustomizers = configurationCustomizersProvider.getIfAvailable();
        this.mybatisPlusPropertiesCustomizers = mybatisPlusPropertiesCustomizerProvider.getIfAvailable();
        this.applicationContext = applicationContext;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    当然,我们也可以使用 ObjectProvider#getIfAvailable() 来实现类似 required=false 的功能,这是 @Lazy 提供不了能力。
    比如:

    @Service
    public class B {
    
        @Autowired
        private ObjectProvider<A> aProvider;
    
        public void doBiz(){
            A a = this.aProvider.getIfAvailable();
            if (a == null) {
                log.info("a is null");
                return;
            }
            a.m1();
        }
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    @Lazy 只能延迟注入,但如果容器中没有这个 bean 的话,在使用时,是会报错的。
    所以,ObjectFactory 提供的功能是同 @Lazy 等价的。而 ObjectProvider 可以额外提供 required=false 的能力

    小结

    ObjectProvider 和 ObjectFactory 都可以提供类似 @Lazy 延迟注入的功能。
    另外,ObjectProvider#getIfAvailable() 还可以提供类似 required=false 的功能。

  • 相关阅读:
    SpringBoot 打包发布
    计算机算法分析与设计(12)---贪心算法(最优装载问题和哈夫曼编码问题)
    security 会话并发管理
    更改Maven项目中pom.xml文件的版本号
    『航班乘客满意度』场景数据分析建模与业务归因解释 ⛵
    二十二、MySQL联合查询
    【学习笔记】Kafka学习
    寒冬已逝,“量子春天”正来
    无涯教程-JavaScript - IMDIV函数
    【人工智能】知识表示
  • 原文地址:https://blog.csdn.net/wang489687009/article/details/126234857