使用 AOP 作用域代理在单例 bean 中自动装配原型 bean
Using AOP scoped proxy to autowire prototype bean in a singleton bean
我能够测试自动装配原型 bean,在单例 bean 中只会创建一个原型 bean。
作为解决方案,我读到我可以为原型 bean 定义 AOP 范围的代理或使用 Spring 的查找方法注入。
这是我尝试过的 -
PrototypeBean.java
@Component
@Scope(value = ConfigurableBeanFactory.SCOPE_PROTOTYPE, proxyMode = ScopedProxyMode.INTERFACES)
public class PrototypeBean implements Prototype {
private String welcomeMessage;
public String getWelcomeMessage() {
return welcomeMessage;
}
public void setWelcomeMessage(final String welcomeMessage) {
this.welcomeMessage = welcomeMessage;
}
}
SingletonBean.java
@Component
public class SingletonBean implements Singleton{
@Autowired private Prototype prototype;
public Prototype getPrototype() {
return prototype;
}
public void greet() {
System.out.println(prototype.getWelcomeMessage());
}
}
测试Class
public class AutowiredDependenciesDemo {
@Autowired private Singleton autowiredSingleton;
@Autowired ConfigurableApplicationContext context;
@Test
public void testPrototypeBeanWithAopScopedProxy(){
Assert.assertNotNull(autowiredSingleton);
Prototype prototypeBean = (Prototype) ((SingletonBean) autowiredSingleton).getPrototype();
prototypeBean.setWelcomeMessage("hello world");
autowiredSingleton.greet();
Singleton contextSingleton = (Singleton) context.getBean("singletonBean");
Assert.assertSame(autowiredSingleton, contextSingleton);
Prototype anotherPrototypeBean = (Prototype) ((SingletonBean)contextSingleton).getPrototype();
anotherPrototypeBean.setWelcomeMessage("hello india");
contextSingleton.greet();
autowiredSingleton.greet();
// i expected both the prototype instances to be different. in the debugger, it does show two different 'proxied' instances. however the test fails.
Assert.assertNotSame(prototypeBean, anotherPrototypeBean);
}
我是不是漏掉了什么?此外,对 greet() 方法的调用 return null.
您在考虑代理和原型 bean 时会混入一些东西。
当 Spring Framework 将 Prototype Scoped bean 注入到 Singleton Scoped bean 中时,它会创建一个 Proxy 对象(实现所有必需的接口)并注入它而不是 Prototype bean 的实例。然后,每当在此原型代理上调用方法时,Spring 都会创建一个新实例并在这个新实例上调用该方法。
在你的情况下——在测试中——你只比较注入的代理,它们是相同的,因为原型 Bean 只存在 1 个代理,这个代理负责在需要时创建原型 Bean 的新实例。
这是我的例子:
我有一个接口 Prototype 及其实现 PrototypeImpl。在我的测试中,我直接从 ApplicationContext 获取 Prototype 类型的 bean,我还使用 @Autowired 注入它。然后在调试器中我看到这个:
请注意,只有一个相同的 Proxy(查看其地址),但在此代理上调用 'toString()' 会显示 PrototypeImpl 对象的两个不同地址。这正是我上面写的内容。
编辑:关于取消代理的信息
要扩展 M.Deinum 的评论,您可以通过以下方式从代理中提取底层对象:
Prototype extracted = null;
if(AopUtils.isAopProxy(a) && a instanceof Advised) {
Object target = ((Advised)a).getTargetSource().getTarget();
extracted = (Prototype) target;
}
我能够测试自动装配原型 bean,在单例 bean 中只会创建一个原型 bean。
作为解决方案,我读到我可以为原型 bean 定义 AOP 范围的代理或使用 Spring 的查找方法注入。
这是我尝试过的 -
PrototypeBean.java
@Component
@Scope(value = ConfigurableBeanFactory.SCOPE_PROTOTYPE, proxyMode = ScopedProxyMode.INTERFACES)
public class PrototypeBean implements Prototype {
private String welcomeMessage;
public String getWelcomeMessage() {
return welcomeMessage;
}
public void setWelcomeMessage(final String welcomeMessage) {
this.welcomeMessage = welcomeMessage;
}
}
SingletonBean.java
@Component
public class SingletonBean implements Singleton{
@Autowired private Prototype prototype;
public Prototype getPrototype() {
return prototype;
}
public void greet() {
System.out.println(prototype.getWelcomeMessage());
}
}
测试Class
public class AutowiredDependenciesDemo {
@Autowired private Singleton autowiredSingleton;
@Autowired ConfigurableApplicationContext context;
@Test
public void testPrototypeBeanWithAopScopedProxy(){
Assert.assertNotNull(autowiredSingleton);
Prototype prototypeBean = (Prototype) ((SingletonBean) autowiredSingleton).getPrototype();
prototypeBean.setWelcomeMessage("hello world");
autowiredSingleton.greet();
Singleton contextSingleton = (Singleton) context.getBean("singletonBean");
Assert.assertSame(autowiredSingleton, contextSingleton);
Prototype anotherPrototypeBean = (Prototype) ((SingletonBean)contextSingleton).getPrototype();
anotherPrototypeBean.setWelcomeMessage("hello india");
contextSingleton.greet();
autowiredSingleton.greet();
// i expected both the prototype instances to be different. in the debugger, it does show two different 'proxied' instances. however the test fails.
Assert.assertNotSame(prototypeBean, anotherPrototypeBean);
}
我是不是漏掉了什么?此外,对 greet() 方法的调用 return null.
您在考虑代理和原型 bean 时会混入一些东西。
当 Spring Framework 将 Prototype Scoped bean 注入到 Singleton Scoped bean 中时,它会创建一个 Proxy 对象(实现所有必需的接口)并注入它而不是 Prototype bean 的实例。然后,每当在此原型代理上调用方法时,Spring 都会创建一个新实例并在这个新实例上调用该方法。
在你的情况下——在测试中——你只比较注入的代理,它们是相同的,因为原型 Bean 只存在 1 个代理,这个代理负责在需要时创建原型 Bean 的新实例。
这是我的例子: 我有一个接口 Prototype 及其实现 PrototypeImpl。在我的测试中,我直接从 ApplicationContext 获取 Prototype 类型的 bean,我还使用 @Autowired 注入它。然后在调试器中我看到这个:
请注意,只有一个相同的 Proxy(查看其地址),但在此代理上调用 'toString()' 会显示 PrototypeImpl 对象的两个不同地址。这正是我上面写的内容。
编辑:关于取消代理的信息
要扩展 M.Deinum 的评论,您可以通过以下方式从代理中提取底层对象:
Prototype extracted = null;
if(AopUtils.isAopProxy(a) && a instanceof Advised) {
Object target = ((Advised)a).getTargetSource().getTarget();
extracted = (Prototype) target;
}