ObjectProvider<T> 是 Spring 框架(从 Spring 5 开始)中用于延迟获取 Bean 的一个接口,位于 org.springframework.beans.factory 包下。它是对 ObjectFactory<T> 的增强版,提供了更灵活的方式来获取和筛选容器中的 Bean。
ObjectProvider 使用场景
延迟依赖查找 :允许在需要时才获取依赖对象,而不是在应用启动时
安全地获取可选依赖项(Optional-like Behavior) :更灵活地获取特定类型的所有 Bean
避免循环依赖问题 :通过延迟加载可以帮助解决构造器循环依赖场景
获取多个匹配的 Bean
延迟依赖查找 ObjectProvider 可以延迟获取某个 Bean,而不是在注入时立即初始化。这在某些场景下可以提升性能,尤其是当 Bean 的创建成本较高或者可能不会被用到的时候。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 public class MyService { private final ObjectProvider<HeavyResource> heavyResourceProvider; public MyService (ObjectProvider<HeavyResource> heavyResourceProvider) { this .heavyResourceProvider = heavyResourceProvider; } public void doSomething () { HeavyResource resource = heavyResourceProvider.getIfAvailable(); if (resource != null ) { resource.use(); } } }
获取多个Bean 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 @Bean @ConditionalOnMissingBean public RedisDelayQueueManager redisDelayQueueManager ( StringRedisTemplate redisTemplate, DelayQueueProperties properties, ObjectProvider<List<DelayQueueListener<?>>> listenersProvider) { RedisDelayQueueManager manager = new RedisDelayQueueManager (redisTemplate, properties); List<DelayQueueListener<?>> listeners = listenersProvider.getIfAvailable(Collections::emptyList); for (DelayQueueListener<?> listener : listeners) { manager.addListener(listener); } return manager; }
安全地获取可选依赖项(Optional-like Behavior)
getIfAvailable():如果存在该 Bean,则返回它;否则返回 null。
getIfUnique():如果存在且只有一个该类型的 Bean,则返回;否则返回 null 或抛出异常。
stream():返回所有匹配的 Bean 的流式接口,方便筛选。
缓解构造循环依赖问题 在 Spring 中,常见的循环依赖有:
构造器注入引起的循环依赖(无法自动处理)
字段/Setter 注入引起的循环依赖(Spring 可以处理)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 Componentpublic class A { private final ObjectProvider<B> bProvider; @Autowired public A (ObjectProvider<B> bProvider) { this .bProvider = bProvider; } public void doSomething () { B b = bProvider.getIfAvailable(); b.doSomethingElse(); } }@Component public class B { private final ObjectProvider<A> aProvider; @Autowired public B (ObjectProvider<A> aProvider) { this .aProvider = aProvider; } public void doSomethingElse () { A a = aProvider.getIfAvailable(); a.doSomething(); } }
构造器只注入了 ObjectProvider<B> 和 ObjectProvider<A>,它们是轻量级的封装对象。只有在使用 B 或 A 是在业务方法内部调用 getIfAvailable() 时才发生的。此时 Spring 已经完成了部分 Bean 的创建流程,可能已经可以安全地获取到目标 Bean。
ObjectProvider 与 Spring 解决循环依赖机制的区别:Spring 使用三级缓存 + 提前暴露工厂引用 的方式处理字段Setter注入的循环依赖。而 ObjectProvider 则是从另一个角度——延迟加载和解耦——辅助减少构造器注入导致的循环依赖。
在遇到循环引用问题时应该优化遵循如下规范:
优先使用字段/Setter 注入:Spring 更容易管理其生命周期和依赖关系。
遇到构造器注入循环时考虑重构:
提取公共接口或抽象类;
拆分职责;
引入事件驱动、观察者等模式。
谨慎使用 ObjectProvider 来延迟加载 Bean:
适用于可选依赖、策略模式、懒加载场景;
不推荐滥用为绕开循环依赖的快捷方式
ObjectProvider 与 @Autowired(required=false) 的区别 虽然 @Autowired(required=false) 也能处理可选依赖,但 ObjectProvider 提供了更多优势:
支持延迟查找,只在调用 getObject() 等方法时才实际查找 Bean
提供更丰富的 API(如 getIfAvailable(Supplier), ifAvailable(Consumer) 等)
能够获取集合类型的依赖并进行进一步处理
更适合在自动配置类和条件性逻辑中使用
ObjectProvider实现 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 public interface ObjectProvider <T> extends ObjectFactory <T>, Iterable<T> { T getObject (Object... args) throws BeansException; @Nullable T getIfAvailable () throws BeansException; default T getIfAvailable (Supplier<T> defaultSupplier) throws BeansException { T dependency = getIfAvailable(); return (dependency != null ? dependency : defaultSupplier.get()); } default void ifAvailable (Consumer<T> dependencyConsumer) throws BeansException { T dependency = getIfAvailable(); if (dependency != null ) { dependencyConsumer.accept(dependency); } } @Nullable T getIfUnique () throws BeansException; 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); } } @Override default Iterator<T> iterator () { return stream().iterator(); } default Stream<T> stream () { throw new UnsupportedOperationException ("Multi element access not supported" ); } default Stream<T> orderedStream () { throw new UnsupportedOperationException ("Ordered element access not supported" ); } }