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


前言

当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();
	}
  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
Spring AOP中的JDK动态代理是一种实现动态代理的方式。它通过使用JDK的Proxy类和InvocationHandler接口来生成代理对象和处理代理逻辑。具体来说,当我们使用Spring AOP时,代理对象的生成直接使用了JDK动态代理的Proxy.newProxyInstance方法。而代理逻辑则是通过实现了InvocationHandler接口的invoke方法来实现的。在Spring AOP中,JdkDynamicAopProxy类实现了InvocationHandler接口,并完成了Spring AOP拦截器链拦截等一系列逻辑。通过JdkDynamicAopProxy的invoke方法,我们可以在目标方法执行前后添加额外的逻辑。这种方式的优点是可以在运行时动态地生成代理对象,不需要事先编写代理类的代码。这样可以更加灵活地实现横切关注点的功能,并且可以避免代码冗余。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *3* [Spring AOP --JDK动态代理方式](https://blog.csdn.net/m0_46195271/article/details/108714116)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *2* [SpringAOP JDK动态代理](https://blog.csdn.net/weixin_46281472/article/details/125629339)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

躺平程序猿

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值