Spring-ObjectProvider基础与原理

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
Component
public 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> {

// 返回指定类型的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");
}
}

Spring-ObjectProvider基础与原理
http://example.com/2025/06/11/spring-ObjectProvider基础与原理/
作者
ares
发布于
2025年6月11日
许可协议