Lookup Method Injection 是 Spring 提供的原生机制,通过 CGLIB 动态代理重写单例 Bean 的 public abstract 无参方法,使其每次调用都从容器获取新的 Prototype Bean 实例;推荐优先使用 ObjectProvider 替代,更简洁、无侵入、易测试。

在 Spring 中,单例 Bean 默认无法直接持有原型(Prototype)Bean 的引用,因为单例 Bean 初始化时会注入一次依赖,之后该引用就固定了。若想每次调用时都获取一个新的 Prototype Bean 实例,需借助 Lookup Method Injection(查找方法注入)——这是 Spring 提供的原生机制,专为解决“单例中使用原型”的场景。
什么是 Lookup Method Injection?
Lookup Method Injection 是 Spring 容器通过 CGLIB 动态代理,在运行时重写单例 Bean 的某个抽象方法,使其每次调用都从容器中重新 getBean() 获取新实例。它不要求 Bean 实现接口,也不依赖构造器或 setter,而是基于方法签名由容器接管实现。
关键要求:
- 目标方法必须是 public abstract(不能是 final 或 private)
- 方法不能有参数(Spring 5.1+ 支持带参数的 lookup,但推荐无参以保持语义清晰)
- 返回类型必须是 Spring 容器中已注册的 Prototype Bean 类型
- 类不能是 final(否则 CGLIB 无法生成子类)
配置方式:XML + 抽象方法(传统标准做法)
定义单例 Service:
立即学习“Java免费学习笔记(深入)”;
public abstract class OrderService {
// 每次调用此方法,都会获取新的 Validator 实例
public abstract Validator getValidator();
<pre class="brush:php;toolbar:false;">public void process(Order order) {
Validator validator = getValidator(); // ✅ 每次都是新对象
validator.validate(order);
// ...
}}
定义原型 Validator:
@Component
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public class OrderValidator implements Validator {
public OrderValidator() {
System.out.println("OrderValidator created: " + this);
}
@Override
public void validate(Order order) { /* ... */ }
}XML 配置(Spring 5.2+ 仍支持,且最直观体现 lookup 语义):
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
<bean id="orderService" class="com.example.OrderService">
<lookup-method name="getValidator" bean="orderValidator"/>
</bean>
<p><bean id="orderValidator" class="com.example.OrderValidator" scope="prototype"/>注解方式:@Lookup(更现代、推荐)
Spring 3.1+ 支持 @Lookup 注解替代 XML。只需在抽象方法上标注:
@Service
public abstract class OrderService {
<pre class="brush:php;toolbar:false;">@Lookup // ← 关键:告诉 Spring 此方法由容器动态实现
public abstract Validator getValidator();
public void process(Order order) {
Validator v = getValidator(); // 每次调用都 new 一个 orderValidator 实例
v.validate(order);
}}
确保 Validator 是 prototype 作用域:
@Component
@Scope(SCOPE_PROTOTYPE)
public class OrderValidator implements Validator { ... }⚠️ 注意:@Lookup 方法必须是 abstract,且所在类不能被 @Configuration 标记(否则可能触发代理冲突);若类是 @Component,需保证它由 Spring 扫描管理(非 new 出来的实例)。
替代方案对比(为什么优先选 Lookup 而非其他)
常见误区做法及问题:
- 直接注入 Prototype Bean 字段:只注入一次,后续始终是同一个实例(违反 prototype 语义)
- 注入 ApplicationContext 并手动 getBean():可行但耦合容器 API,测试困难,且易忽略线程安全或作用域上下文问题
-
使用 ObjectProvider
:Spring 4.3+ 推荐轻量方案,代码更简洁,无需抽象类和代理
ObjectProvider 示例(更灵活、无侵入):
@Service
public class OrderService {
private final ObjectProvider<Validator> validatorProvider;
<pre class="brush:php;toolbar:false;">public OrderService(ObjectProvider<Validator> validatorProvider) {
this.validatorProvider = validatorProvider;
}
public void process(Order order) {
Validator v = validatorProvider.getObject(); // ✅ 每次都新实例
v.validate(order);
}}
✅ 这种方式不强制抽象、不依赖 CGLIB、可测试性强,是当前更主流的推荐做法,尤其适合新项目。

















