Spring事务三:cglib方式代理,this调用不生效本质

基于自己之前对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是没有关系的。

 

おすすめ

転載: blog.csdn.net/Aqu415/article/details/111098425
おすすめ