源码分析基于spring 4.3.x
本文承接上一篇文章对Spring AOP的分析,继续分析spring如何对AOP中多个通知进行链式调用的。
关于阅读源码的思路,可参考 -- 如何阅读java源码
《Spring源码解析 -- AOP原理(1)》 中说了,JdkDynamicAopProxy实现了InvocationHandler,正是这个类调用AOP通知中定义的增强方法。
JdkDynamicAopProxy#invoke
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { MethodInvocation invocation; Object oldProxy = null; boolean setProxyContext = false; TargetSource targetSource = this.advised.targetSource; Class<?> targetClass = null; Object target = null; try { ... // #1 Object retVal; if (this.advised.exposeProxy) { oldProxy = AopContext.setCurrentProxy(proxy); setProxyContext = true; } target = targetSource.getTarget(); if (target != null) { targetClass = target.getClass(); } List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass); // #2 if (chain.isEmpty()) { Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args); retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse); // #3 } else { invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain); // #4 retVal = invocation.proceed(); // #5 } Class<?> returnType = method.getReturnType(); if (retVal != null && retVal == target && returnType != Object.class && returnType.isInstance(proxy) && !RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) { // #6 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()) { targetSource.releaseTarget(target); } if (setProxyContext) { AopContext.setCurrentProxy(oldProxy); } } }
#1
处理equals/hashCode等方法,直接调用目标方法
#2
getInterceptorsAndDynamicInterceptionAdvice -- 获取方法拦截器
#3
没有方法拦截器,直接调用目标方法
#4
构造调用链ReflectiveMethodInvocation
#5
调用调用链
#6
处理特殊场景 -- 方法返回值为this
AdvisedSupport#getInterceptorsAndDynamicInterceptionAdvice -> DefaultAdvisorChainFactory#getInterceptorsAndDynamicInterceptionAdvice
public List<Object> getInterceptorsAndDynamicInterceptionAdvice( Advised config, Method method, Class<?> targetClass) { // This is somewhat tricky... We have to process introductions first, // but we need to preserve order in the ultimate list. List<Object> interceptorList = new ArrayList<Object>(config.getAdvisors().length); Class<?> actualClass = (targetClass != null ? targetClass : method.getDeclaringClass()); boolean hasIntroductions = hasMatchingIntroductions(config, actualClass); AdvisorAdapterRegistry registry = GlobalAdvisorAdapterRegistry.getInstance(); for (Advisor advisor : config.getAdvisors()) { if (advisor instanceof PointcutAdvisor) { // Add it conditionally. PointcutAdvisor pointcutAdvisor = (PointcutAdvisor) advisor; if (config.isPreFiltered() || pointcutAdvisor.getPointcut().getClassFilter().matches(actualClass)) { // #1 MethodInterceptor[] interceptors = registry.getInterceptors(advisor); // #2 MethodMatcher mm = pointcutAdvisor.getPointcut().getMethodMatcher(); if (MethodMatchers.matches(mm, method, actualClass, hasIntroductions)) { // #3 if (mm.isRuntime()) { // #4 // Creating a new object instance in the getInterceptors() method // isn't a problem as we normally cache created chains. for (MethodInterceptor interceptor : interceptors) { interceptorList.add(new InterceptorAndDynamicMethodMatcher(interceptor, mm)); // #5 } } else { interceptorList.addAll(Arrays.asList(interceptors)); // #6 } } } } else if (advisor instanceof IntroductionAdvisor) { IntroductionAdvisor ia = (IntroductionAdvisor) advisor; if (config.isPreFiltered() || ia.getClassFilter().matches(actualClass)) { Interceptor[] interceptors = registry.getInterceptors(advisor); interceptorList.addAll(Arrays.asList(interceptors)); } } else { Interceptor[] interceptors = registry.getInterceptors(advisor); interceptorList.addAll(Arrays.asList(interceptors)); } } return interceptorList; }
#1
判断class是否匹配pointcut
#2
getInterceptors -- 将advisor转化为MethodInterceptor方法拦截器,MethodInterceptor#invoke负责调用被拦截的方法
#3
判断method是否匹配pointcut
#4
是否运行时判断
#5
添加InterceptorAndDynamicMethodMatcher到结果
#6
添加MethodInterceptor到结果
DefaultAdvisorAdapterRegistry#getInterceptors:
public MethodInterceptor[] getInterceptors(Advisor advisor) throws UnknownAdviceTypeException { List<MethodInterceptor> interceptors = new ArrayList<MethodInterceptor>(3); Advice advice = advisor.getAdvice(); if (advice instanceof MethodInterceptor) { interceptors.add((MethodInterceptor) advice); } for (AdvisorAdapter adapter : this.adapters) { if (adapter.supportsAdvice(advice)) { interceptors.add(adapter.getInterceptor(advisor)); } } if (interceptors.isEmpty()) { throw new UnknownAdviceTypeException(advisor.getAdvice()); } return interceptors.toArray(new MethodInterceptor[interceptors.size()]); }
有三个Advice没有实现MethodInterceptor,通过DefaultAdvisorAdapterRegistry#adapters适配
public DefaultAdvisorAdapterRegistry() { registerAdvisorAdapter(new MethodBeforeAdviceAdapter()); registerAdvisorAdapter(new AfterReturningAdviceAdapter()); registerAdvisorAdapter(new ThrowsAdviceAdapter()); }
回到JdkDynamicAopProxy#invoke方法 #5
步骤,调用调用链
ReflectiveMethodInvocation#proceed
public Object proceed() throws Throwable { // We start with an index of -1 and increment early. if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) { // #1 return invokeJoinpoint(); // #2 } Object interceptorOrInterceptionAdvice = this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex); //#3 if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) { //#4 ... } 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); //#5 } }
#1
判断是否到拦截器链末尾,注意currentInterceptorIndex初始值是-1
#2
拦截器已经调用完,调用被拦截的方法
#3
获取下一个拦截器
#4
是否为需要运行时判断
#5
直接调用拦截器
调用链ReflectiveMethodInvocation中的节点是拦截器MethodInterceptor。
ReflectiveMethodInvocation#proceed方法会获取下一个拦截器,并调用MethodInterceptor#invoke方法。
注意,调用拦截器MethodInterceptor#invoke方法时会将调用链ReflectiveMethodInvocation作为参数,拦截器MethodInterceptor#invoke执行完逻辑后,又调用ReflectiveMethodInvocation#proceed,继续调用下一个拦截器。
看看AspectJAroundAdvice的实现
public Object invoke(MethodInvocation mi) throws Throwable { if (!(mi instanceof ProxyMethodInvocation)) { throw new IllegalStateException("MethodInvocation is not a Spring ProxyMethodInvocation: " + mi); } ProxyMethodInvocation pmi = (ProxyMethodInvocation) mi; // #1 ProceedingJoinPoint pjp = lazyGetProceedingJoinPoint(pmi); // #2 JoinPointMatch jpm = getJoinPointMatch(pmi); return invokeAdviceMethod(pjp, jpm, null, null); // #3 }
#1
获取调用链
#2
使用调用链构造一个MethodInvocationProceedingJoinPoint
#3
调用增强方法
protected Object invokeAdviceMethod(JoinPoint jp, JoinPointMatch jpMatch, Object returnValue, Throwable t) throws Throwable { return invokeAdviceMethodWithGivenArgs(argBinding(jp, jpMatch, returnValue, t)); // #1 }
#1
invokeAdviceMethodWithGivenArgs -- 通过反射调用增强方法,就是执行Around通知
argBinding -- 负责参数绑定
AbstractAspectJAdvice#argBinding
protected Object[] argBinding(JoinPoint jp, JoinPointMatch jpMatch, Object returnValue, Throwable ex) { calculateArgumentBindings(); //#1 // AMC start Object[] adviceInvocationArgs = new Object[this.parameterTypes.length]; int numBound = 0; if (this.joinPointArgumentIndex != -1) { //#2 adviceInvocationArgs[this.joinPointArgumentIndex] = jp; numBound++; } else if (this.joinPointStaticPartArgumentIndex != -1) { adviceInvocationArgs[this.joinPointStaticPartArgumentIndex] = jp.getStaticPart(); numBound++; } if (!CollectionUtils.isEmpty(this.argumentBindings)) { //#3 // binding from pointcut match if (jpMatch != null) { PointcutParameter[] parameterBindings = jpMatch.getParameterBindings(); for (PointcutParameter parameter : parameterBindings) { String name = parameter.getName(); Integer index = this.argumentBindings.get(name); adviceInvocationArgs[index] = parameter.getBinding(); numBound++; } } // binding from returning clause if (this.returningName != null) { Integer index = this.argumentBindings.get(this.returningName); adviceInvocationArgs[index] = returnValue; numBound++; } // binding from thrown exception if (this.throwingName != null) { Integer index = this.argumentBindings.get(this.throwingName); adviceInvocationArgs[index] = ex; numBound++; } } if (numBound != this.parameterTypes.length) { throw new IllegalStateException("Required to bind " + this.parameterTypes.length + " arguments, but only bound " + numBound + " (JoinPointMatch " + (jpMatch == null ? "was NOT" : "WAS") + " bound in invocation)"); } return adviceInvocationArgs; }
#1
通过反射获取参数名,返回名等信息,设置joinPointArgumentIndex,argumentBindings等属性
#2
添加JoinPointMatch到增强方法的参数中
#3
添加被拦截方法参数,返回值,异常等数据到增强方法的参数中
在环绕通知中,我们需要编写如下代码
@Around("...") public Object methodAroundLog(ProceedingJoinPoint joinPoint) throws Throwable { Object result = joinPoint.proceed(joinPoint.getArgs()); return result; }
这里 joinPoint.proceed(joinPoint.getArgs());
调用了下一个拦截器(MethodInvocationProceedingJoinPoint#proceed会调用ReflectiveMethodInvocation#proceed),这样才能继续调用拦截器调用链。
@Before通知会调用MethodBeforeAdviceInterceptor
public Object invoke(MethodInvocation mi) throws Throwable { this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis() ); // #1 return mi.proceed(); // #2 }
#1
执行@Before增强
#2
继续拦截器调用链
@After通知会调用AspectJAfterThrowingAdvice
public Object invoke(MethodInvocation mi) throws Throwable { try { return mi.proceed(); // #1 } catch (Throwable ex) { if (shouldInvokeOnThrowing(ex)) { invokeAdviceMethod(getJoinPointMatch(), null, ex); // #2 } throw ex; } }
#1
先调用拦截器链
#2
执行@After增强
到这里,spring aop的源码解析就完成了。
这部分还是挺复杂的,需要耐心点看源码。
如果您觉得本文不错,欢迎关注我的微信公众号,您的关注是我坚持的动力!