正如我们所知,Spring 使用代理来添加功能(@Transactional例如@Scheduled)。有两种选择 - 使用 JDK 动态代理(该类必须实现非空接口),或使用 CGLIB 代码生成器生成子类。我一直认为 proxyMode 允许我在 JDK 动态代理和 CGLIB 之间进行选择。
但我能够创建一个例子来表明我的假设是错误的:
情况1:
单例:
@Service
public class MyBeanA {
@Autowired
private MyBeanB myBeanB;
public void foo() {
System.out.println(myBeanB.getCounter());
}
public MyBeanB getMyBeanB() {
return myBeanB;
}
}
原型:
@Service
@Scope(value = "prototype")
public class MyBeanB {
private static final AtomicLong COUNTER = new AtomicLong(0);
private Long index;
public MyBeanB() {
index = COUNTER.getAndIncrement();
System.out.println("constructor invocation:" + index);
}
@Transactional // just to force Spring to create a proxy
public long getCounter() {
return index;
}
}
主要的:
MyBeanA beanA = context.getBean(MyBeanA.class);
beanA.foo();
beanA.foo();
MyBeanB myBeanB = beanA.getMyBeanB();
System.out.println("counter: " + myBeanB.getCounter() + ", class=" + myBeanB.getClass());
输出:
constructor invocation:0
0
0
counter: 0, class=class test.pack.MyBeanB$$EnhancerBySpringCGLIB$$2f3d648e
在这里我们可以看到两件事:
MyBeanB
仅被实例化一次。
为了添加 的@Transactional
功能MyBeanB
,Spring 使用了 CGLIB。
案例2:
让我纠正一下MyBeanB定义:
@Service
@Scope(value = "prototype", proxyMode = ScopedProxyMode.TARGET_CLASS)
public class MyBeanB {
在这种情况下,输出是:
constructor invocation:0
0
constructor invocation:1
1
constructor invocation:2
counter: 2, class=class test.pack.MyBeanB$$EnhancerBySpringCGLIB$$b06d71f2
在这里我们可以看到两件事:
MyBeanB被实例化3次。
为了添加 的@Transactional功能MyBeanB,Spring 使用了 CGLIB。
你能解释一下发生了什么事吗?代理模式到底如何工作?
芜湖不芜
相关分类