Reputation: 23780
This is the code I have:
SpringConfiguration:
package biz.tugay;
/* User: [email protected] Date: 25/12/15 Time: 19:30 */
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
@Configuration
@ComponentScan(basePackages = "biz.tugay")
public class SpringConfiguration {
}
Foo:
package biz.tugay;
/* User: [email protected] Date: 25/12/15 Time: 19:36 */
public interface Foo {
String getState();
}
FooImpl:
package biz.tugay;
/* User: [email protected] Date: 25/12/15 Time: 19:31 */
import org.springframework.context.annotation.Scope;
import org.springframework.context.annotation.ScopedProxyMode;
import org.springframework.stereotype.Component;
import java.util.UUID;
@Component
@Scope(value = "prototype", proxyMode = ScopedProxyMode.TARGET_CLASS)
public class FooImpl implements Foo {
private final String state = UUID.randomUUID().toString();
public String getState() {
return state;
}
}
Bar:
package biz.tugay;
/* User: [email protected] Date: 25/12/15 Time: 19:35 */
public interface Bar {
Foo getFoo();
}
BarImpl:
package biz.tugay;
/* User: [email protected] Date: 25/12/15 Time: 19:33 */
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
@Component
@Scope(value = "singleton")
public class BarImpl implements Bar {
private Foo foo;
@Autowired
public void setFoo(Foo foo) {
this.foo = foo;
}
public Foo getFoo() {
return foo;
}
}
and the Test Class:
package biz.tugay;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import static java.lang.System.out;
public class TestClass {
final static Class<SpringConfiguration> SPRING_CONFIGURATION_CLASS = SpringConfiguration.class;
public static void main(String[] args) {
final ApplicationContext applicationContext;
applicationContext = new AnnotationConfigApplicationContext(SPRING_CONFIGURATION_CLASS);
final Bar barOne = applicationContext.getBean(BarImpl.class);
final Bar barTwo = applicationContext.getBean(BarImpl.class);
out.println("barOne == barTwo: " + (barOne == barTwo));
out.println("barOne.getFoo == barTwo.getFoo: " + (barOne.getFoo() == barTwo.getFoo()));
out.println(barOne.getFoo().getState());
out.println(barTwo.getFoo().getState());
}
}
And the output will be:
barOne == barTwo: true
barOne.getFoo == barTwo.getFoo: true
064bdb74-cad7-4d13-86fe-a4fc0021e5a0
c6f2d9be-09b4-456d-9414-8ece2f2acc9e
My question is,
I understand that 064bdb74-cad7-4d13-86fe-a4fc0021e5a0 is not equal to c6f2d9be-09b4-456d-9414-8ece2f2acc9e because FooImpl is actually ScopedProxy.
What I do not understand is, how come barOne.getFoo can be equal to barTwo.getFoo?
How is this possible:
barOne.getFoo() == barTwo.getFoo()
barOne.getFoo().getState() != barTwo().getFoo().getState()
???
Upvotes: 1
Views: 688
Reputation: 7646
To unterstand the output at first you need to understand how and what is doing the Spring Framework. Lets start with the idea that when you are injecting "short lived" scope bean into a "long lived" scope bean (in your case the prototype bean into singleton bean) Spring injects an AOP proxy in place of the scoped bean.
That is, you need to inject a proxy object that exposes the same public interface as the scoped object but that can also retrieve the real target object from the relevant scope (such as an HTTP request) and delegate method calls onto the real object.
Basically there are two main types of proxies the JDK proxy and CGLIB proxies (default).
So lets go back to the example code and try to understand what is going on ...
When your application starts Spring Framework creates two beans the Foo
and the Bar
but both beans are not just a simple implementations (FooImpl and BarImpl) but are proxies (the CglibAopProxy's).
So in your TestClass
class you have 2 references to the same AopProxy of BarImpl
the barOne and barTwo. As the Bar
is scoped as singleton the underling target class of the AopProxy is the same object (BarImpl) which is pre-inililized. And this Bar
AopProxy has a injected AopPorxy of type Foo
, so when you are executing following code barOne.getFoo() == barTwo.getFoo()
it evaluates to true, as both barOne
and barTwo
have the same instance of AopProxy (not the target class), but when you are calling the barTwo().getFoo().getState()
the AopProxy is creating a new instance of target class (FooImpl) and exeutes the getState()
method on it. So each call to the bar.getFoo().getState()
will create a new instance of FooImpl
and then execute its getState()
method.
Upvotes: 3
Reputation: 287
Highlight of code:
The result is expected. why?
Upvotes: 0