Reputation: 7413
As other SO answers suggested, use proxy mode type as per your need, I am still confused;
@Configuration
@ComponentScan
public class Application
{
public static void main( String[] args )
{
ApplicationContext context = new AnnotationConfigApplicationContext(Application.class);
PrototypeBeanFactory factoryBean = context.getBean(PrototypeBeanFactory.class);
System.out.println("Let's start");
SomeInterface b1 = factoryBean.getPrototypeBeanInstance();
SomeInterface b2 = factoryBean.getPrototypeBeanInstance();
System.out.println(b1.hashCode());
System.out.println(b2.hashCode());
b1.sayHello();
b2.sayHello();
b1.sayHello();
b2.sayHello();
}
}
@Component
public class PrototypeBeanFactory {
@Lookup
public PrototypeBean getPrototypeBeanInstance(){
System.out.println("It'll be ignored");
return null;
}
}
@Component
@Scope(value="prototype", proxyMode = ScopedProxyMode.INTERFACES)
public class PrototypeBean {
public PrototypeBean() {
System.out.println("I am created");
}
public void sayHello() {
System.out.println("Hello from " + this.hashCode());
}
}
Output
Let's start
I am created
I am created
1849201180
1691875296
Hello from 1849201180
Hello from 1691875296
Hello from 1849201180
Hello from 1691875296
Now if I change the proxy-mode to TARGET_CLASS
Output
Let's start
-721204056
-721204056
I am created
Hello from 172032696
I am created
Hello from 299644693
I am created
Hello from 1771243284
I am created
Hello from 2052256418
Why, in case of class based proxy, it creates different object on each method invocation?
Upvotes: 9
Views: 22916
Reputation: 701
I created an interface PrototypeBeanI with sayHello and used the interface in the main(), still different results. seems that using PrototypeBeanI or PrototypeBean as the variable type does not create any difference.
Upvotes: 0
Reputation: 125232
@Component
@Scope(value="prototype", proxyMode = ScopedProxyMode.INTERFACES)
public class PrototypeBean { ... }
This, in your case, will lead to a bean per invocation of getBean
bean as your PrototypeBean
doesn't implement an interface and as such a scoped proxy cannot be created. In your case you call the lookup method twice and hence you will get 2 instances. This is actually the normal behavior of a prototype
scoped bean.
Component
@Scope(value="prototype", proxyMode = ScopedProxyMode.TARGET_CLASS)
public class PrototypeBean { ... }
This will lead to the creation of a proxy. That proxy is created once and will be returned for each call to getBean
. As soon as you invoke a method on the proxy it will, based on the scope, either create a new one or reuse an existing one. As you have specified the scope as prototype
each method invocation will lead to a new object.
Note: If your class would implement an interface which exposes the appropriate method, there would be no difference in the behavior of proxyMode = ScopedProxyMode.INTERFACES
and proxyMode = ScopedProxyMode.TARGET_CLASS
as in both cases a scoped proxy would be created.
Upvotes: 21