SpringAOP之代理对象的执行(JDK动态代理为例)

2023-01-09 09:36:28

前言

当AOP增强后的代理Bean执行切入点方法时会进入JdkDynamicAopProxy的invoke方法


提示:以下是本篇文章正文内容,下面案例可供参考

1.首先看下切面类,当前有前置、后置、完成后置、异常四种通知。Spring解析时会解析为四个通知器(advisor)

@Aspect
@Component
public class MyAspect {

    @Pointcut(value = "execution(* *..service.*.*(..))")
    public void p1(){

    }

    @Before(value = "p1()",argNames = "aa")
    public void before(JoinPoint aa){
        for (Object arg : aa.getArgs()) {
            System.out.println(arg);
        }
        System.out.println("前置横切逻辑通知");
    }
    @After(value = "p1()")
    public void after(){
        System.out.println("后置横切逻辑通知");
    }

    @AfterReturning(value = "p1()" ,returning="result")
    public void afterReturn(Object result){
        System.out.println(result);
        System.out.println("正常返回时横切逻辑通知");
    }

    @AfterThrowing(value = "p1()",throwing = "throwable")
    public void Exception(Throwable throwable){
        System.out.println(throwable.fillInStackTrace());
        System.out.println("发生异常时横切逻辑通知");
    }
}

2.当代理类的切点方法执行时进入invoke方法

JdkDynamicAopProxy.class
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
		Object oldProxy = null;
		boolean setProxyContext = false;

		TargetSource targetSource = this.advised.targetSource;
		Object target = null;

		try {
			if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {
				// The target does not implement the equals(Object) method itself.
				return equals(args[0]);
			}
			else if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {
				// The target does not implement the hashCode() method itself.
				return hashCode();
			}
			else if (method.getDeclaringClass() == DecoratingProxy.class) {
				// There is only getDecoratedClass() declared -> dispatch to proxy config.
				return AopProxyUtils.ultimateTargetClass(this.advised);
			}
			else if (!this.advised.opaque && method.getDeclaringClass().isInterface() &&
					method.getDeclaringClass().isAssignableFrom(Advised.class)) {
				// Service invocations on ProxyConfig with the proxy config...
				return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args);
			}

			Object retVal;

			if (this.advised.exposeProxy) {
				// Make invocation available if necessary.
				oldProxy = AopContext.setCurrentProxy(proxy);
				setProxyContext = true;
			}

			// Get as late as possible to minimize the time we "own" the target,
			// in case it comes from a pool.
			target = targetSource.getTarget();
			Class<?> targetClass = (target != null ? target.getClass() : null);

			// Get the interception chain for this method.
			// 获取方法的切面/通知器链 此处切面链有五个:1.Spring默认的一个;2.before的;3.after的,4AfterReturning的,5AfterThrowing的
			List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);

			// Check whether we have any advice. If we don't, we can fallback on direct
			// reflective invocation of the target, and avoid creating a MethodInvocation.
			if (chain.isEmpty()) {
				// 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);
				retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
			}
			else {
				// We need to create a method invocation...
				// 获取切面链方法执行器(经典)
				MethodInvocation invocation =
						new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
				// Proceed to the joinpoint through the interceptor chain.
				// 方法执行器执行(内执行切面方法)
				retVal = invocation.proceed();
			}

			// Massage return value if necessary.
			Class<?> returnType = method.getReturnType();
			if (retVal != null && retVal == target &&
					returnType != Object.class && returnType.isInstance(proxy) &&
					!RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) {
				// Special case: it returned "this" and the return type of the method
				// is type-compatible. Note that we can't help if the target sets
				// a reference to itself in another returned object.
				retVal = proxy;
			}
			else if (retVal == null && returnType != Void.TYPE && returnType.isPrimitive()) {
				throw new AopInvocationException(
						"Null return value from advice does not match primitive return type for: " + method);
			}
			return retVal;
		}
		finally {
			if (target != null && !targetSource.isStatic()) {
				// Must have come from TargetSource.
				targetSource.releaseTarget(target);
			}
			if (setProxyContext) {
				// Restore old proxy.
				AopContext.setCurrentProxy(oldProxy);
			}
		}
	}

3.进入invocation.proceed()方法,获取第i个通知器,并执行其定义好的invoke方法,此处每个invoke方法都有一个ReflectiveMethodInvocation参数,传入当前线程在步骤2中创建的方法执行器MethodInvocation,方便通知器完成各自逻辑后回调MethodInvocation#proceed方法进入下个通知器逻辑。

ReflectiveMethodInvocation.class

public Object proceed() throws Throwable {
		// We start with an index of -1 and increment early.
		if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
			return invokeJoinpoint();
		}
		// 获取拦截器链子中的第i个拦截器(一个线程一个ReflectiveMethodInvocation否则线程不安全)
		Object interceptorOrInterceptionAdvice =
				this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
		if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
			// Evaluate dynamic method matcher here: static part will already have
			// been evaluated and found to match.
			InterceptorAndDynamicMethodMatcher dm =
					(InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;
			Class<?> targetClass = (this.targetClass != null ? this.targetClass : this.method.getDeclaringClass());
			if (dm.methodMatcher.matches(this.method, targetClass, this.arguments)) {
				return dm.interceptor.invoke(this);
			}
			else {
				// Dynamic matching failed.
				// Skip this interceptor and invoke the next in the chain.
				return proceed();
			}
		}
		else {
			// It's an interceptor, so we just invoke it: The pointcut will have
			// been evaluated statically before this object was constructed.
			// 执行通知器的invoke方法
			return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
		}
	}

4.下面按执行顺序依次进入五个通知器方法

4.1 ExposeInvocationInterceptor通知器Spring自带的

public Object invoke(MethodInvocation mi) throws Throwable {
		MethodInvocation oldInvocation = invocation.get();
		invocation.set(mi);
		try {
		// 回调方法执行器的proceed()方法又回到3中。
			return mi.proceed();
		}
		finally {
			invocation.set(oldInvocation);
		}
	}

4.2 ExposeInvocationInterceptor执行完逻辑后回调方法执行器的proceed()方法又回到步骤3中进入第二个通知器AspectJAfterThrowingAdvice

public Object invoke(MethodInvocation mi) throws Throwable {
		try {
		// 回调MethodInvocation#proceed方法
			return mi.proceed();
		}
		catch (Throwable ex) {
			if (shouldInvokeOnThrowing(ex)) {
			// MyAspect中的Exception方法
				invokeAdviceMethod(getJoinPointMatch(), null, ex);
			}
			throw ex;
		}
	}

4.3AspectJAfterThrowingAdvice执行完逻辑后回调方法执行器的proceed()方法又回到步骤3中进入第三个通知器AfterReturningAdviceInterceptor

public Object invoke(MethodInvocation mi) throws Throwable {
// 回调MethodInvocation#proceed方法
		Object retVal = mi.proceed();
		// MyAspect中的afterReturn方法
		this.advice.afterReturning(retVal, mi.getMethod(), mi.getArguments(), mi.getThis());
		return retVal;
	}

4.4AfterReturningAdviceInterceptor执行完逻辑后回调方法执行器的proceed()方法又回到步骤3中进入第四个通知器AspectJAfterAdvice

public Object invoke(MethodInvocation mi) throws Throwable {
		try {
		// 回调MethodInvocation#proceed方法
			return mi.proceed();
		}
		finally {
		// MyAspect中的after方法
			invokeAdviceMethod(getJoinPointMatch(), null, null);
		}
	}

4.5 AspectJAfterAdvice执行完逻辑后回调方法执行器的proceed()方法又回到步骤3中进入第四个通知器MethodBeforeAdviceInterceptor

public Object invoke(MethodInvocation mi) throws Throwable {
		// MyAspect中的before方法
		this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis());
		// 回调MethodInvocation#proceed方法
		return mi.proceed();
	}
  • 作者:躺平程序猿
  • 原文链接:https://blog.csdn.net/yangxiaofei_java/article/details/112091663
    更新时间:2023-01-09 09:36:28