1. 程式人生 > >spring--aop_2_原始碼分析之MethodInterceptor

spring--aop_2_原始碼分析之MethodInterceptor

前提:

前兩篇分析了aop 兩種方式實現的大致流程和方式,在這兩種實現方式中都有一個很重要的方法獲取攔截器鏈
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
所有的aop增強方法都封裝在一個個攔截器中,然後根據這個攔截器鏈的呼叫進行增強。

此方法的實現是在advised 物件實現的(advised 是 AdvisedSupport 物件的例項,ProxyFactoryBean 是AdvisedSupport 子類)
 

public List<Object> getInterceptorsAndDynamicInterceptionAdvice(Method method, @Nullable Class<?> targetClass) {
	MethodCacheKey cacheKey = new MethodCacheKey(method);
	//這裡使用了快取來提高效率,第一次獲取還是要建立的。
	//使用了 advisorChainFactory 生成攔截器鏈,advisorChainFactory 是 DefaultAdvisorChainFactory 的例項
	List<Object> cached = this.methodCache.get(cacheKey);
	if (cached == null) {
		cached = this.advisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice(
				this, method, targetClass);
		this.methodCache.put(cacheKey, cached);
	}
	return cached;
}

advisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice()原始碼:

@Override
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.
	//初始化攔截器鏈,大小是通知器個數。這個配置就是 ProxyFactoryBean 的 interceptNames 的屬性配置。
	List<Object> interceptorList = new ArrayList<>(config.getAdvisors().length);
	
	Class<?> actualClass = (targetClass != null ? targetClass : method.getDeclaringClass());
	boolean hasIntroductions = hasMatchingIntroductions(config, actualClass);
	
	//獲取 AdvisorAdapterRegistry 例項,AdvisorAdapterRegistry被稱為“註冊器”
	//利用它來對從ProxyFactoryBean 配置中得到的通知器進行適配,從而獲得相應的攔截器,再把攔截器加入到攔截器鏈中
	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)) {
			
				//通過  AdvisorAdapterRegistry 獲取攔截器,這個方法封裝了advice 織入的實現入口
				MethodInterceptor[] interceptors = registry.getInterceptors(advisor);
				
				//獲取 MethodMatcher ,用來匹配目標方法,如果匹配就放入到攔截器鏈中。pointcut 就是在這裡使用的
				MethodMatcher mm = pointcutAdvisor.getPointcut().getMethodMatcher();
				if (MethodMatchers.matches(mm, method, actualClass, hasIntroductions)) {
					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;
}

通過GlobalAdvisorAdapterRegistry 獲取一個單例的 AdvisorAdapterRegistry 例項
AdvisorAdapterRegistry 的實現是 DefaultAdvisorAdapterRegistry
DefaultAdvisorAdapterRegistry.getInterceptors() 方法封裝了advice 織入實現的入口

注:在ProxyFactoryBean 中已經把配置的advice封裝成了 Advisor,第一篇有介紹。

DefaultAdvisorAdapterRegistry 類原始碼分析:

public class DefaultAdvisorAdapterRegistry implements AdvisorAdapterRegistry, Serializable {

	//advisor 介面卡列表
	private final List<AdvisorAdapter> adapters = new ArrayList<>(3);


	/**
	 * Create a new DefaultAdvisorAdapterRegistry, registering well-known adapters.
		定義了3個介面卡, 就是這3個介面卡為aop提供編織能力。
		這3個介面卡和spring aop提供的advice增強功能相對就的
		這3個是spring aop advice的封裝實現
	 */
	public DefaultAdvisorAdapterRegistry() {
		registerAdvisorAdapter(new MethodBeforeAdviceAdapter());
		registerAdvisorAdapter(new AfterReturningAdviceAdapter());
		registerAdvisorAdapter(new ThrowsAdviceAdapter());
	}
	
	//省略方法......

	@Override
	public MethodInterceptor[] getInterceptors(Advisor advisor) throws UnknownAdviceTypeException {

		List<MethodInterceptor> interceptors = new ArrayList<>(3);
		//從advisor通知器中獲取advice通知
		Advice advice = advisor.getAdvice();
		if (advice instanceof MethodInterceptor) {
			//如果是MethodInterceptor 直接加入到MethodInterceptor list 中不需要適配
			interceptors.add((MethodInterceptor) advice);
		}
		//對通知器進行適配,使用構造時已經配置好的adapter(上面3種adapter)
		//然後從對應的adapter 中取出封裝好的aop編織功能的攔截器
		//通過adapter.getInterceptor() 方法返回對應的是3種 MethodInterceptor。
		//這裡就是第一篇分析的invoke獲取攔截器鏈呼叫的 MethodInterceptor
		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]);
	}

	//可以自己定義adapter
	@Override
	public void registerAdvisorAdapter(AdvisorAdapter adapter) {
		this.adapters.add(adapter);
	}
}

adapter 有三種實現方式
這裡使用MethodBeforeAdviceAdapter說明:就是判斷一下advice型別,然後把advice 封裝成MethodInterceptor
 

class MethodBeforeAdviceAdapter implements AdvisorAdapter, Serializable {

	//這裡驗證是否是 MethodBeforeAdvice 型別
	@Override
	public boolean supportsAdvice(Advice advice) {
		return (advice instanceof MethodBeforeAdvice);
	}
	
	@Override
	public MethodInterceptor getInterceptor(Advisor advisor) {
		//獲取advice,建立 MethodBeforeAdviceInterceptor 物件並返回
		MethodBeforeAdvice advice = (MethodBeforeAdvice) advisor.getAdvice();
		return new MethodBeforeAdviceInterceptor(advice);
	}
}

這裡獲取了advisor 對應的 MethodInterceptor之後,就要對這MethodInterceptor 進行匹配了
匹配使用的是通過 advisor.getPointcut().getMethodMatcher() 獲取到 MethodMatcher 物件進行匹配驗證的。

總結:
    通過配置 ProxyFactoryBean interceptorNames 屬性來配置advice,ProxyFactoryBean 呼叫 initializeAdvisorChain() 方法把這些配置解析成 advisor鏈(advisor 包含了advice 和 pointcut)。
    在代理物件呼叫目標方法時,通過 DefaultAdvisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice() 方法獲取到攔截器鏈,這個方法又是呼叫 DefaultAdvisorAdapterRegistry.getInterceptors() 方法生成的攔截器鏈。
    spring aop 就是通過攔截器模式呼叫這些生成的攔截器實現的aop功能