使用AOP作用域代理在单例bean

时间:2015-08-30 11:20:58

标签: java spring dependency-injection proxy spring-aop

我能够测试自动装配原型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());
}
}

测试类

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()方法的调用返回null。

1 个答案:

答案 0 :(得分:6)

在你对Proxies和原型bean的思考中,你会混合一些东西。

当Spring Framework将Prototype Scoped bean注入Singleton Scoped bean时,它会创建一个Proxy对象(实现所有必需的接口)并注入它而不是Prototype bean的实例。然后,只要在这个Prototype Proxy上调用方法,Spring就会创建一个新实例,并在这个新实例上调用该方法。

在您的情况下 - 在测试中 - 您只比较注入的代理并且它们是相同的,因为原型Bean只存在一个代理,并且此代理负责在需要时创建原型Bean的新实例。

这是我的例子: 我有一个接口Prototype及其实现PrototypeImpl。在我的测试中,我直接从ApplicationContext获取Prototype类型的bean,我也使用@Autowired注入它。然后在调试器中我看到了:

enter image description here

请注意,只有一个相同的Proxy(查看其地址),但在此代理上调用'toString()'会显示PrototypeImpl对象的两个不同地址。这完全显示了我上面写的内容。

编辑:有关取消代理的信息

要扩展M. Deinum的评论,您可以通过以下方式从代理提取基础对象:

Prototype extracted = null;

if(AopUtils.isAopProxy(a) && a instanceof Advised) {
    Object target = ((Advised)a).getTargetSource().getTarget();
    extracted = (Prototype) target;
}