【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;
}

当然,我们也可以使用 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();
    }

}

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

小结

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

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

老王学源码

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值