Spring事务三:cglib方式代理,this调用不生效本质
基于自己之前对Spring代理生成的认知,大致的认为采用cglib框架生成目标类的子类;在父类方法体内使用this应该也是调用代理类的实例,那么容器应该能感知方法上的注解进而执行拦截(比如事务拦截器),但是事与愿违用this调用的没有让事务拦截生效。先来看我的定势思维想象:假设有父类F和子类Spublic class F {public void first() {this.second();}p
基于自己之前对Spring代理生成的认知,大致的认为采用cglib框架生成目标类的子类;在父类方法体内使用this应该也是调用代理类的实例,那么容器应该能感知方法上的注解进而执行拦截(比如事务拦截器),但是事与愿违用this调用的没有让事务拦截生效。
先来看我的定势思维想象:假设有父类F和子类S
public class F {
public void first() {
this.second();
}
public void second() {
}
public static void main(String[] args) {
S s = new S();
s.first();
}
}
class S extends F {
}
那么执行man方法时,first方法里的this肯定是S的实例;
刚开始我以为spring 里代理子类与真实目标父类的关系就如此简单,实则不然:cglib子类与目标父类确确实实是有继承关系(这是cglib框架决定的),但还存在一层组合关系(这是代理拦截逻辑实现的)!
CglibAopProxy
cglib动态代理生成是这个类来实现的,调用生成代理的链路如下:
org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator#createProxy
->
org.springframework.aop.framework.ProxyFactory#getProxy(java.lang.ClassLoader)
->
org.springframework.aop.framework.ProxyCreatorSupport#createAopProxy//将自己的实例传给AopProxy子类(JdkDynamicAopProxy或者ObjenesisCglibAopProxy,该类继承了CglibAopProxy)的protected final AdvisedSupport advised;属性
->
org.springframework.aop.framework.JdkDynamicAopProxy#getProxy(java.lang.ClassLoader)//这里我们直接跳到cglib实现类,这个方法主要功能是组装拦截器,然后调用cglib框架(貌似spring把cglib框架的代码收为己用了)生成子类
组装拦截器的方法里有一个核心的点:
Callback[] callbacks = getCallbacks(rootClass); 这里会组装大名鼎鼎的 DynamicAdvisedInterceptor 传给cglib框架,所有后续所有的方法拦截都是通过该类来实现的(暂且这样认为,至少部分是它拦截的);
// Choose an "aop" interceptor (used for AOP calls).
Callback aopInterceptor = new DynamicAdvisedInterceptor(this.advised);
我们来到该类的核心方法,也就是这篇文章揭秘的核心
org.springframework.aop.framework.CglibAopProxy.DynamicAdvisedInterceptor#intercept
@Override
public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
Object oldProxy = null;
boolean setProxyContext = false;
Class<?> targetClass = null;
Object target = null;
try {
if (this.advised.exposeProxy) {
// Make invocation available if necessary.
oldProxy = AopContext.setCurrentProxy(proxy);
setProxyContext = true;
}
// May be null. Get as late as possible to minimize the time we
// "own" the target, in case it comes from a pool...
target = getTarget();
if (target != null) {
targetClass = target.getClass();
}
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
Object retVal;
// Check whether we only have one InvokerInterceptor: that is,
// no real advice, but just reflective invocation of the target.
if (chain.isEmpty() && Modifier.isPublic(method.getModifiers())) {
// We can skip creating a MethodInvocation: just invoke the target directly.
// Note that the final invoker must be an InvokerInterceptor, so we know
// it does nothing but a reflective operation on the target, and no hot
// swapping or fancy proxying.
Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
//******@A******
retVal = methodProxy.invoke(target, argsToUse);
}
else {
// We need to create a method invocation...
retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed();
}
retVal = processReturnType(proxy, target, method, retVal);
return retVal;
}
finally {
if (target != null) {
releaseTarget(target);
}
if (setProxyContext) {
// Restore old proxy.
AopContext.setCurrentProxy(oldProxy);
}
}
}
在上面标记星号的地方,框架取出了target对象并执行了对应方法;这个target正是被代理的原始目标类!!!恍然大悟,cglib模式下的内存中对象生成布局应该是这样的
1、会有cglib子类对象SON(注意这里是对象)
2、拦截器对象I
3、真实目标表类对象PARENT
调用流程应该是 SON->I->PARENT,并不是我开始理解的 SON->I->SON;所以在父类方法里的this就是PARENT,与SON是没有关系的。
更多推荐
所有评论(0)