Spring源码解析 -- AOP原理(2)

Spring源码解析 -- 读取bean元数据
spring源码解析 -- 构造bean
spring源码解析 -- 注入属性
spring源码解析 -- Spring Context
Spring源码解析 -- AOP原理(1)
Spring源码解析 -- AOP原理(2)
Spring源码解析 -- SpringMvc原理java

源码分析基于spring 4.3.x
本文承接上一篇文章对Spring AOP的分析,继续分析spring如何对AOP中多个通知进行链式调用的。
关于阅读源码的思路,可参考 -- 如何阅读java源码spring

《Spring源码解析 -- AOP原理(1)》 中说了,JdkDynamicAopProxy实现了InvocationHandler,正是这个类调用AOP通知中定义的加强方法。 JdkDynamicAopProxy#invokebash

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到结果post

DefaultAdvisorAdapterRegistry#getInterceptors:ui

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适配this

public DefaultAdvisorAdapterRegistry() {
		registerAdvisorAdapter(new MethodBeforeAdviceAdapter());
		registerAdvisorAdapter(new AfterReturningAdviceAdapter());
		registerAdvisorAdapter(new ThrowsAdviceAdapter());
	}
复制代码

回到JdkDynamicAopProxy#invoke方法#5步骤,调用调用链 ReflectiveMethodInvocation#proceedlua

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 直接调用拦截器spa

调用链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的源码解析就完成了。
这部分仍是挺复杂的,须要耐心点看源码。

若是您以为本文不错,欢迎关注个人微信公众号,您的关注是我坚持的动力!

相关文章
相关标签/搜索