Spring深度解析-15、AOP拦截器链实现原理

在上一篇章的学习中了解到AOP代理对象的执行过程,AOP中的代理对象有JDK代理与CGLIB代理两种方式,这两种代理对象在对目标对象的方法进行拦截,分别通过JdkDynamicAopProxy的invoke和DynamicAdvisedInterceptor的intercept来拦截。
这两种的原理是一致的:
1、先判断有没有拦截器链,如果没有,那么直接执行目标对象的方法
2、如果有拦截器链,则封装成ReflectiveMethodInvocation,执行proceed方法依次调用拦截器,然后返回目标方法执行的结果。
今天就来看看AOP的拦截器链是如何实现的。

拦截器链如何拦截

关于AOP拦截器链的实现,当然是通过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) {
			// 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.
			return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
		}
	}

拦截器链的调用是这样的:
依次匹配各个拦截器,如果匹配成功,则执行这个拦截器,否则继续往后面匹配,直到所有拦截器都执行完毕,则调用目标对象的方法。

看到这个,刚开始有点疑惑。
1、拦截器执行完毕才调用目标对象?这只是前置增强,那么后置增强呢,异常增强呢??
2、这里看到匹配了拦截器以后,直接return 拦截器执行的结果,难道只能匹配一个拦截器??而且神奇的是,这样匹配后直接return了,那目标方法岂不是没有调用??

OK,这一切的疑惑,都要从拦截器的invoke去理解,解答~~
因此这里需要搞清楚interceptorsAndDynamicMethodMatchers,也就是这一系列拦截器是从哪里引入进来的。

interceptorsAndDynamicMethodMatchers

这一系列拦截器,由ReflectiveMethodInvocation的构造器传入,回到上一篇学习的代理对象的执行过程,我们可以追溯到拦截器链的获取代码:

List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);

而这里的advised,是AdvisedSupport,我们继续点进去看

public List<Object> getInterceptorsAndDynamicInterceptionAdvice(Method method, @Nullable Class<?> targetClass) {
		MethodCacheKey cacheKey = new MethodCacheKey(method);
		List<Object> cached = this.methodCache.get(cacheKey);
		if (cached == null) {
		//拦截器链从advisorChainFactory去取。
			cached = this.advisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice(
					this, method, targetClass);
			this.methodCache.put(cacheKey, cached);
		}
		return cached;
	}

这里可以看到拦截器链,是从advisorChainFactory中获取的,同时AdvisedSupport还对拦截器链做了缓存。
再看this.advisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice

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

		// This is somewhat tricky... We have to process introductions first,
		// but we need to preserve order in the ultimate list.
		//这里得到的是DefaultAdvisorAdapterRegistry
		//在这里面注册了前置后置异常增强通知的适配器
		//而这个适配器的作用:
		//一方面用来判断通知的类型
		//另一个方法把通知包装进指定的拦截器
		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;
		//遍历通知
		for (Advisor advisor : advisors) {
		//如果是一个PointcutAdvisor,那么通知与切点都有了,这里需要去判断方法是否匹配这个pointCut,匹配就把这个加进拦截器链
			if (advisor instanceof PointcutAdvisor) {
				// Add it conditionally.
				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);
						}
						match = ((IntroductionAwareMethodMatcher) mm).matches(method, actualClass, hasIntroductions);
					}
					else {
						match = mm.matches(method, actualClass);
					}
					if (match) {
					
						MethodInterceptor[] interceptors = registry.getInterceptors(advisor);
						if (mm.isRuntime()) {
							// 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));
							}
						}
						else {
							interceptorList.addAll(Arrays.asList(interceptors));
						}
					}
				}
			}
			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;
	}

getInterceptorsAndDynamicInterceptionAdvice中如果实现拦截器链的获取呢,主要关注registry.getInterceptors(advisor);
这个registry是一个DefaultAdvisorAdapterRegistry对象,并且在对象创建的时候,就注册了三个代理对象,

	public DefaultAdvisorAdapterRegistry() {

		registerAdvisorAdapter(new MethodBeforeAdviceAdapter());
		registerAdvisorAdapter(new AfterReturningAdviceAdapter());
		registerAdvisorAdapter(new ThrowsAdviceAdapter());
	}

getInterceptors

public MethodInterceptor[] getInterceptors(Advisor advisor) throws UnknownAdviceTypeException {
		List<MethodInterceptor> interceptors = new ArrayList<>(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[0]);
	}

这里以MethodBeforeAdviceAdapter为例来看一下如何获取拦截器

class MethodBeforeAdviceAdapter implements AdvisorAdapter, Serializable {

	@Override
	//如果是前置通知,那么可以通过这个对象来得到拦截器
	public boolean supportsAdvice(Advice advice) {
		return (advice instanceof MethodBeforeAdvice);
	}

	@Override
	public MethodInterceptor getInterceptor(Advisor advisor) {
		MethodBeforeAdvice advice = (MethodBeforeAdvice) advisor.getAdvice();
//这是最终获取到的拦截器对象,也就是最终调用的invoke就是MethodBeforeAdviceInterceptor的invoke
		return new MethodBeforeAdviceInterceptor(advice);
	}

}

下面来看下,剥丝抽茧后最终得到的MethodBeforeAdviceInterceptor

public class MethodBeforeAdviceInterceptor implements MethodInterceptor, BeforeAdvice, Serializable {

	private final MethodBeforeAdvice advice;


	/**
	 * Create a new MethodBeforeAdviceInterceptor for the given advice.
	 * @param advice the MethodBeforeAdvice to wrap
	 */
	public MethodBeforeAdviceInterceptor(MethodBeforeAdvice advice) {
		Assert.notNull(advice, "Advice must not be null");
		this.advice = advice;
	}


	@Override
	public Object invoke(MethodInvocation mi) throws Throwable {
	//先调用before实现前置增强
		this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis());
		//再去调用proceed进行下一个拦截器的执行
		return mi.proceed();
	}

}

至于后置与异常增强的适配器与相应的拦截器都是一样的原理,
在适配器里判断是否是对应的增强类型,在通过getInterceptor方法获取到对应的拦截器。
后置增强:

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();
		}
		catch (Throwable ex) {
			Method handlerMethod = getExceptionHandler(ex);
			if (handlerMethod != null) {
				invokeHandlerMethod(mi, ex, handlerMethod);
			}
			throw ex;
		}
	}
    原文作者:AOP
    原文地址: https://blog.csdn.net/qq_28605513/article/details/86256319
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞