单例对象在初始化时只会注入一次原型对象,后续即使原型对象本身是多例的,单例对象中持有的引用也不会更新。所以在单例对象中注入原型对象需要经过特殊处理。
@Lookup方法注入
通过定义一个抽象方法,Spring 会动态生成子类并覆盖该方法,每次调用时从容器中获取新的原型实例。
在单例 Bean 中定义一个抽象方法,并用
@Lookup
标注;方法返回类型为原型 Bean 的类型;
@Component @Scope("prototype") public class PrototypeBean { public void doSomething() { System.out.println("Prototype instance: " + this.hashCode()); } } @Service public abstract class SingletonService { // 可以是抽象类 // 通过 @Lookup 动态获取 PrototypeBean @Lookup public abstract PrototypeBean getPrototypeBean(); public void usePrototype() { PrototypeBean prototypeBean = getPrototypeBean(); // 每次调用都会返回新的实例 prototypeBean.doSomething(); } }
@Scope代理模式
通过为原型 Bean 创建代理对象,每次调用时代理会委托给新的真实实例。
在原型 Bean 上添加
@Scope
并指定代理模式为TARGET_CLASS
(基于 CGLIB 代理);单例 Bean 直接注入原型 Bean,但实际调用时会动态获取新实例;
@Component @Scope(value = "prototype", proxyMode = ScopedProxyMode.TARGET_CLASS) // 关键配置 public class PrototypeBean { public void doSomething() { System.out.println("Prototype instance: " + this.hashCode()); } } @Service public class SingletonService { @Autowired private PrototypeBean prototypeBean; // 注入的是代理对象 public void usePrototype() { prototypeBean.doSomething(); // 每次调用都会触发代理,返回新的实例 } }
ObjectProvider 延迟注入
通过 ObjectProvider
(Spring 5+)或 JSR-330 的 Provider
接口,显式获取原型实例。
注入
ObjectProvider<PrototypeBean>
或Provider<PrototypeBean>
;调用
getObject()
或get()
方法获取新实例;@Service public class SingletonService { @Autowired private ObjectProvider<PrototypeBean> prototypeBeanProvider; // Spring 方式 // 或使用 JSR-330 的 Provider(需依赖 javax.inject) // @Autowired // private Provider<PrototypeBean> prototypeBeanProvider; public void usePrototype() { PrototypeBean prototypeBean = prototypeBeanProvider.getObject(); // 每次获取新实例 prototypeBean.doSomething(); } }