回首Spring源码之AOP:方法增强(责任链模式)

前言

        在上一篇介绍了spirng aop创建创建动态代理的过程,本片着重分析一下切面方法的执行过程。以JKD动态代理为例。

方法增强(责任链模式)

        来到JDK的动态代理类JdkDynamicAopProxy,它是一个InvocationHandler,JKD动态代理基于InvocationHandler的invoke方法进行方法增强:

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)) {
				//equals方法不需要代理
				return equals(args[0]);
			}
			else if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {
				//hashCode方法不需要代理
				return hashCode();
			}
			else if (method.getDeclaringClass() == DecoratingProxy.class) {
				//若执行的class对象是DecoratingProxy 则不会对其应用切面进行方法的增强。返回源目标类型
				return AopProxyUtils.ultimateTargetClass(this.advised);
			}
			else if (!this.advised.opaque && method.getDeclaringClass().isInterface() &&
					method.getDeclaringClass().isAssignableFrom(Advised.class)) {
				//如果目标对象实现的Advised接口,则不会对其应用切面进行方法的增强,直接执行方法
				return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args);
			}

			Object retVal;

			if (this.advised.exposeProxy) {
				/**
				 * 暴露我们的代理对象到线程变量中,需要搭配@EnableAspectJAutoProxy(exposeProxy = true)一起使用.
				 * aop中方法都是被切入的方法,但是在切入的方法中通过
				 * this来调用另外一个方法的时候,那么该方法就不会被代理执行,而是通过方法内部执行
				 * 设置exposeProxy = true可以使上述调用也走代理
				 *事务方法调用事务方法的时候需要设置exposeProxy = true
				 */
				oldProxy = AopContext.setCurrentProxy(proxy);
				setProxyContext = true;
			}

			target = targetSource.getTarget();
			Class<?> targetClass = (target != null ? target.getClass() : null);

			//构建方法拦截器责任链
			List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
MethodInvocation.
			if (chain.isEmpty()) {
				//为空则直接调用目标方法,不过一般这里不会为空,还记得在匹配方法获得的advisor集合么
				//spring会额外加入一个ExposeInvocationInterceptor,这个Interceptor总能匹配成功
				Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
				retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
			}
			else {
				//创建一个MethodInvocation对象
				MethodInvocation invocation =
						new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
				//使用MethodInvocation进行责任链的调用
				retVal = invocation.proceed();
			}

			Class<?> returnType = method.getReturnType();
			if (retVal != null && retVal == target &&
					returnType != Object.class && returnType.isInstance(proxy) &&
					!RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) {
				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);
			}
		}
、}

        首先是构建目标方法的拦截器责任链this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass):

public List<Object> getInterceptorsAndDynamicInterceptionAdvice(Method method, @Nullable Class<?> targetClass) {
		MethodCacheKey cacheKey = new MethodCacheKey(method);
		//先从缓存中取
		List<Object> cached = this.methodCache.get(cacheKey);
		if (cached == null) {
			//缓存没有则构建拦截器链
			cached = this.advisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice(
					this, method, targetClass);
			this.methodCache.put(cacheKey, cached);
		}
		return cached;
}


public List<Object> getInterceptorsAndDynamicInterceptionAdvice(
			Advised config, Method method, @Nullable Class<?> targetClass) {

		//获取通知器适配器注册中心
		AdvisorAdapterRegistry registry = GlobalAdvisorAdapterRegistry.getInstance();
		//拿到当前方法的通知器
		Advisor[] advisors = config.getAdvisors();
		List<Object> interceptorList = new ArrayList<>(advisors.length);
		Class<?> actualClass = (targetClass != null ? targetClass : method.getDeclaringClass());
		Boolean hasIntroductions = null;

		//遍历每个Advisor,把Advisor转换成拦截器MethodInterceptor
		for (Advisor advisor : advisors) {
			if (advisor instanceof PointcutAdvisor) {
				//一般都为PointcutAdvisor
				PointcutAdvisor pointcutAdvisor = (PointcutAdvisor) advisor;
				if (config.isPreFiltered() || pointcutAdvisor.getPointcut().getClassFilter().matches(actualClass)) {
					MethodMatcher mm = pointcutAdvisor.getPointcut().getMethodMatcher();
					boolean match;
					if (mm instanceof IntroductionAwareMethodMatcher) {
						if (hasIntroductions == null) {
							hasIntroductions = hasMatchingIntroductions(advisors, actualClass);
						}
						//判断该Advisor是否能够匹配当前方法
						match = ((IntroductionAwareMethodMatcher) mm).matches(method, actualClass, hasIntroductions);
					}
					else {
						match = mm.matches(method, actualClass);
					}
					if (match) {
						//如果能够匹配,获取advisor对应的MethodInterceptor
						MethodInterceptor[] interceptors = registry.getInterceptors(advisor);
						if (mm.isRuntime()) {
							for (MethodInterceptor interceptor : interceptors) {
								interceptorList.add(new InterceptorAndDynamicMethodMatcher(interceptor, mm));
							}
						}
						else {
							interceptorList.addAll(Arrays.asList(interceptors));
						}
					}
				}
			}
			else if (advisor instanceof IntroductionAdvisor) {
				//Introduction就不看了
				IntroductionAdvisor ia = (IntroductionAdvisor) advisor;
				if (config.isPreFiltered() || ia.getClassFilter().matches(actualClass)) {
					Interceptor[] interceptors = registry.getInterceptors(advisor);
					interceptorList.addAll(Arrays.asList(interceptors));
				}
			}
			else {
				//如果不是PointcutAdvisor,也能处理,只要有对应的适配器的支持
				Interceptor[] interceptors = registry.getInterceptors(advisor);
				interceptorList.addAll(Arrays.asList(interceptors));
			}
		}

		return interceptorList;
}

看下如何从AdvisorAdapterRegistry中获取拦截器:

public MethodInterceptor[] getInterceptors(Advisor advisor) throws UnknownAdviceTypeException {
		List<MethodInterceptor> interceptors = new ArrayList<>(3);
		Advice advice = advisor.getAdvice();
		if (advice instanceof MethodInterceptor) {
			//如果通知就是MethodInterceptor,就不用转换了
			interceptors.add((MethodInterceptor) advice);
		}
		for (AdvisorAdapter adapter : this.adapters) {
			if (adapter.supportsAdvice(advice)) {
				//如果有存在支持的适配器,则用适配器转换成MethodInterceptor
				interceptors.add(adapter.getInterceptor(advisor));
			}
		}
		if (interceptors.isEmpty()) {
			throw new UnknownAdviceTypeException(advisor.getAdvice());
		}
		return interceptors.toArray(new MethodInterceptor[0]);
}

关于这个通知器的适配器,看一个before通知的例子(MethodBeforeAdviceAdapter):

public boolean supportsAdvice(Advice advice) {
		//支持MethodBeforeAdvice
		return (advice instanceof MethodBeforeAdvice);
	}

	@Override
	public MethodInterceptor getInterceptor(Advisor advisor) {
		MethodBeforeAdvice advice = (MethodBeforeAdvice) advisor.getAdvice();
		//返回对应MethodBeforeAdvice的MethodInterceptor
		return new MethodBeforeAdviceInterceptor(advice);
}

        然后是重头戏,拦截器责任链的调用,我们的源目标方法会在拦截器的最后一个,也就是会在最后一个调用。看一下拦截器的顺序:ExposeInvocationInterceptor,AspectJAfterThrowingAdvice,AfterReturningAdviceInterceptor,AspectJAfterAdvice,AspectJAfterAdvice,AspectJAroundAdvice,MethodBeforeAdviceInterceptor。其中环绕通知和前置通知的顺序不是固定的,有兴趣的可以自己实验一下,当然,通常我们不会同时加让环绕通知和前置通知。进入方法执行,ReflectiveMethodInvocation#proceed:

public Object proceed() throws Throwable {
		//如果当前拦截器为最后一个,则表示调用目标方法
		if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
			//调用原来对象方法
			return invokeJoinpoint();
		}
		//获取当前拦截器
		Object interceptorOrInterceptionAdvice =
				this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
		if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
			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 {
				return proceed();
			}
		}
		else {
			//从第一个拦截器开始执行,注意把自己当作参数传入
			return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
		}
}

首先是暴露Invocation的拦截器:

public Object invoke(MethodInvocation mi) throws Throwable {
		MethodInvocation oldInvocation = invocation.get();
		//设置当前MethodInvocation到本地线程变量
		invocation.set(mi);
		try {
			//继续调用责任链
			return mi.proceed();
		}
		finally {
			//回复原来的MethodInvocation
			invocation.set(oldInvocation);
		}
}

        在每个拦截器中会执行作为参数传入的MethodInvocation#proceed,又会回到ReflectiveMethodInvocation中,拦截器下标加一,接着执行下一个拦截器的方法,以此类推,形成责任链,接下来是异常通知:

public Object invoke(MethodInvocation mi) throws Throwable {
		try {
			//先继续调用责任链
			return mi.proceed();
		}
		catch (Throwable ex) {
			if (shouldInvokeOnThrowing(ex)) {
				//发生异常则执行异常通知
				invokeAdviceMethod(getJoinPointMatch(), null, ex);
			}
			throw ex;
		}
}

返回通知:

public Object invoke(MethodInvocation mi) throws Throwable {
		//还是先调用责任链
		Object retVal = mi.proceed();
		//返回后执行返回通知
		this.advice.afterReturning(retVal, mi.getMethod(), mi.getArguments(), mi.getThis());
		return retVal;
}

后置通知:

public Object invoke(MethodInvocation mi) throws Throwable {
		try {
			return mi.proceed();
		}
		finally {
            //在finally中执行后置通知
			invokeAdviceMethod(getJoinPointMatch(), null, null);
		}
}

环绕通知会特殊一点:

public Object invoke(MethodInvocation mi) throws Throwable {
		if (!(mi instanceof ProxyMethodInvocation)) {
			throw new IllegalStateException("MethodInvocation is not a Spring ProxyMethodInvocation: " + mi);
		}
		//MethodInvocation转换成ProxyMethodInvocation
		ProxyMethodInvocation pmi = (ProxyMethodInvocation) mi;
		//创建一个ProceedingJoinPoint,作为参数传入invokeAdviceMethod方法,便于在around通知方法中往后执行责任链
		ProceedingJoinPoint pjp = lazyGetProceedingJoinPoint(pmi);
		JoinPointMatch jpm = getJoinPointMatch(pmi);
		//执行环绕通知
		return invokeAdviceMethod(pjp, jpm, null, null);
}


protected Object invokeAdviceMethod(JoinPoint jp, @Nullable JoinPointMatch jpMatch,
			@Nullable Object returnValue, @Nullable Throwable t) throws Throwable {
		//绑定参数,执行环绕通知
		return invokeAdviceMethodWithGivenArgs(argBinding(jp, jpMatch, returnValue, t));
}


protected Object invokeAdviceMethodWithGivenArgs(Object[] args) throws Throwable {
		Object[] actualArgs = args;
		if (this.aspectJAdviceMethod.getParameterCount() == 0) {
			actualArgs = null;
		}
		try {
			//反射执行环绕通知方法,在环绕通知中,先执行环绕前置的方法,然后调用
			//ProceedingJoinPoint#proceed()调用责任链的下一个方法,一般为before通知
			return this.aspectJAdviceMethod.invoke(this.aspectInstanceFactory.getAspectInstance(), actualArgs);
		}
		catch (IllegalArgumentException ex) {
			throw new AopInvocationException("Mismatch on arguments to advice method [" +
					this.aspectJAdviceMethod + "]; pointcut expression [" +
					this.pointcut.getPointcutExpression() + "]", ex);
		}
		catch (InvocationTargetException ex) {
			throw ex.getTargetException();
		}
}

在环绕通知的方法中,调用ProceedingJoinPoint#proceed会继续责任链,来到前置通知:

public Object invoke(MethodInvocation mi) throws Throwable {
		//执行前置通知
		this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis());
		//执行责任链
		return mi.proceed();
}

        拦截器下标更新到最后一个后,执行目标方法,然后在环绕通知中返回,环绕通知继续向下执行,最后方法执行的顺序大概是:

  1. 环绕前置
  2. 前置通知
  3. 环绕后置
  4. 后置通知
  5. 返回通知
  6. 异常通知(有异常的话)

        不过环绕前置和前置通知的顺序也不是固定的,因为在对通知器进行排序的过程中使用的是拓扑排序,有兴趣的小伙伴可以研究一下,笔者也不甚了解。

总结

         spring aop利用切面这个概念实现对目标方法的增强,使用了责任链模式对目标对象的方法进行拦截,至此AOP的源码差不多到这里就结束了。AOP算是整个spring的一个难点了吧,其实spring的声明式事务也是通过AOP实现的,不过并没有用切面的形式,而是直接向容器注册Adsivor,省去了切面的解析。

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值