正如我们所知道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。
你能解释发生了什么吗?代理模式如何真正起作用?
聚苯乙烯
我已阅读文档:
/**
* Specifies whether a component should be configured as a scoped proxy
* and if so, whether the proxy should be interface-based or subclass-based.
* <p>Defaults to {@link ScopedProxyMode#DEFAULT}, which typically indicates
* that no scoped proxy should be created unless a different default
* has been configured at the component-scan instruction level.
* <p>Analogous to {@code <aop:scoped-proxy/>} support in Spring XML.
* @see ScopedProxyMode
*/
但是我不清楚。
更新资料
情况3:
我研究了另一种情况,从中提取了接口MyBeanB
:
public interface MyBeanBInterface {
long getCounter();
}
@Service
public class MyBeanA {
@Autowired
private MyBeanBInterface myBeanB;
@Service
@Scope(value = "prototype", proxyMode = ScopedProxyMode.INTERFACES)
public class MyBeanB implements MyBeanBInterface {
在这种情况下,输出为:
constructor invocation:0
0
constructor invocation:1
1
constructor invocation:2
counter: 2, class=class com.sun.proxy.$Proxy92
在这里我们可以看到两件事:
MyBeanB
被实例化3次。- 为了添加的
@Transactional
功能MyBeanB
,Spring使用了JDK动态代理。
MyBeanB
类没有扩展任何接口,因此控制台日志显示CGLIB代理实例也就不足为奇了。在第3种情况下,您引入并实现了一个接口,因此,您获得了JDK代理。您甚至可以在介绍性文字中对此进行描述。
<aop:config proxy-target-class="true">
或配置@EnableAspectJAutoProxy(proxyTargetClass = true)
。