简体   繁体   中英

Using AOP scoped proxy to autowire prototype bean in a singleton bean

I was able to test that autowiring a prototype bean, within a singleton bean results in only a single prototype bean being created.

As a solution to that, I read that I could define AOP scoped proxy for the prototype bean or use Spring's lookup method injection.

Here is what I have tried -

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());
}
}

Test 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);
}

Am I missing something here ? Also, the calls to greet() method return null.

There are things you mix in your thinking about Proxies and prototype beans.

When Spring Framework injects a Prototype Scoped bean into a Singleton Scoped bean then it creates a Proxy object (which implements all required interfaces) and injects it instead of instance of the Prototype bean. Then, whenever method is called on this Prototype Proxy, Spring creates a new instance and the method is called on this new instance.

In your case - in test - you only compare injected Proxies and they are the same because there exists only 1 proxy for the Prototype Bean and this Proxy is responsible for creation of new instance of the Prototype Bean whenever needed.

Here is my example: I have an interface Prototype and its implementation PrototypeImpl. In my test I obtain bean of type Prototype directly from ApplicationContext and I also inject it using @Autowired. Then in debugger I see this:

在此处输入图片说明

Notice that there is only one and the same Proxy (look at its address) but calling 'toString()' on this proxy shows two different addresses of the PrototypeImpl objects. Which shows exactly what I have written above.

EDIT: Info about un-proxying

To extend the comment by M. Deinum you can extract the underlying object from the Proxy in the following way:

Prototype extracted = null;

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM