本文共 4795 字,大约阅读时间需要 15 分钟。
在上一篇文章中,我们对AOP切面解析和代理对象创建有了一个大概的了解,切面和代理对象是没问题了,但是目标方法的调用,以及切面是在什么时候被执行的,我们还需要继续通过源码寻找答案。
调用JdkDynamicAopProxy#invoke(…)方法
首先对代理类执行的方法进行判断,如果是没有重写equals或者hashcode等方法则不进行代理
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)) { return hashCode();}else if{ ……}
判断是否要暴露代理对象,即在@EnableAspectJAutoProxy(exposeProxy = true)标注了true时,会将当前代理对象存入ThreadLocal中,
当需要使用该对象时,可以通过AopContext.currentProxy()调用// 判断是否要暴露代理对象if (this.advised.exposeProxy) { // Make invocation available if necessary. //放入线程本地变量 oldProxy = AopContext.setCurrentProxy(proxy); setProxyContext = true;}
从缓存中获取和当前方法相关的切面拦截链,由于是第一次调用,所以需要将之前解析出来的切面处理成Interceptor类型的对象再返回
List
判断切面拦截链是否为空,如果为空的话直接使用反射调用方法返回结果即可
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); }
由于代码存在before、after、afterReturn、afterThrowing切面,因此进入invocation.proceed()方法,ReflectiveMethodInvocation#proceed该方法也是拦截链的核心逻辑
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();}
判断当前下标是否为拦截链size-1,拦截器的size为5(一个spring自带的和四个自己定义的通知方法),当前下标this.currentInterceptorIndex的默认值为-1,因此如果不存在拦截器的话,size-1的逻辑还是可以正常退出的
if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) { return invokeJoinpoint();}
注意,这里是前++操作,因此拿到的值不会是-1,而是第0个。而这拦截链中第0个对象,是
ExposeInvocationInterceptor。Object interceptorOrInterceptionAdvice = this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
ExposeInvocationInterceptor的类型并不是InterceptorAndDynamicMethodMatcher,因此执行else逻辑,即调用ExposeInvocationInterceptord的invoke方法:
else { // It's an interceptor, so we just invoke it: The pointcut will have // been evaluated statically before this object was constructed. return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);}
ExposeInvocationInterceptor是一个静态单例对象,它在内部提供了一个存放MethodInvocation类型的ThreadLocal变量,用于存储上下文调用。并且它在调用链中总是第一个调用。在mi.proceed();方法中,实际上是ReflectiveMethodInvocation#proceed方法的一次递归
public Object invoke(MethodInvocation mi) throws Throwable { MethodInvocation oldInvocation = invocation.get(); invocation.set(mi); try { return mi.proceed(); } finally { invocation.set(oldInvocation); }}
重复7、8步骤,此时拿到的下标为第1个,因为在该实例中,拦截器一共有五个,其中顺序依次为:ExposeInvocationInterceptor、AfterThrowing、AfterReturn、After、Before,因此此时得到的拦截器为异常通知AfterThrowing,同样执行else逻辑,调用AspectJAfterThrowingAdvice#invoke方法(此处又是一系列的模板方法设计模式的应用)
public Object invoke(MethodInvocation mi) throws Throwable { try { return mi.proceed(); } catch (Throwable ex) { if (shouldInvokeOnThrowing(ex)) { invokeAdviceMethod(getJoinPointMatch(), null, ex); } throw ex; }}
从AspectJAfterThrowingAdvice#invoke方法可以看出,无论后续逻辑出现什么问题,都会被此处的catch语句捕捉,然后判断是否调用异常通知,最后抛出异常。而mi.proceed()方法则是又一次递归
重复7、8步骤,此时拿到的下标为第2个,即返回通知AfterReturn的invoke方法,该方法中通知方法是后于proceed()方法执行的,因此当出现异常时,返回通知是不会被执行到的:
public Object invoke(MethodInvocation mi) throws Throwable { Object retVal = mi.proceed(); this.advice.afterReturning(retVal, mi.getMethod(), mi.getArguments(), mi.getThis()); return retVal;}
继续调用proceed方法,重复7、8步骤,此时拿到的下标为第3个,即后置通知After的invoke方法,从代码中可以看到,该方法是通过try{}finally{}的形式,保证了后置通知无论如何都会被执行到
public Object invoke(MethodInvocation mi) throws Throwable { try { return mi.proceed(); } finally { invokeAdviceMethod(getJoinPointMatch(), null, null); }}
继续调用proceed方法,重复7、8步骤,此时拿到的下标为第4个,即前置通知Before的invoke方法,与afterReturn方法不同的是,它先于目标方法执行,因此前置通知不会受异常影响,并且先于其它通知执行
@Overridepublic Object invoke(MethodInvocation mi) throws Throwable { this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis()); return mi.proceed();}
继续调用proceed方法,需要注意的是,此时this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1条件已经成立,直接执行目标方法。执行完毕之后再根据刚才的调用链执行,完成整个AOP的过程。
Spring在对增强器的处理过程采用了责任链的形式,很好的保证了扩展性,而整个AOP的功能又得益于之前IOC容器设计时预留的接口,我们在学习代码时,不止要知道Spring是怎么做的,还应该多思考Spring为什么是这么做的。
转载地址:http://smfmf.baihongyu.com/