1. 程式人生 > >Spring AOP的實現:Spring AOP攔截器呼叫的實現

Spring AOP的實現:Spring AOP攔截器呼叫的實現

上次我說到關於ProxyFactoryBean物件的getObject方法返回了一個代理物件。剩下的AOP實現過程就和jdk的代理模式相同。通過呼叫這個代理物件的方法(這個方法和目標物件是相同的),但是實際上是呼叫了invoke方法,通過反射來實現方法的增強。

關於jdk如何實現代理模式的反編譯,底層的程式碼實現過程可以在這個部落格中檢視

https://blog.csdn.net/u013815218/article/details/52562536(轉載)

目錄

JDKDynamicAopProxy的invoke攔截

AOP攔截器鏈的呼叫

配置通知器


現在我們來看上次說的JdkDynamicAopProxy的getProxy方法的返回值

Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);

其中這個this指的是InvocationHandler物件,通過對這個介面的invoke方法的重寫,實現了對目標物件的增強。也就是說我們Proxy物件的代理方法被呼叫時,JdkDynamicAopProxy的invoke方法作為Proxy物件的回撥函式而被觸發。那麼實際上真正的增強工作都是在JdkDynamicAopProxy中的invoke方法實現了。

JDKDynamicAopProxy的invoke攔截

原始碼有100多行,所以我就沒有貼上,可以到

org.springframework.aop.framework.JdkDynamicAopProxy中進行檢視。

首先我們要獲得目標物件

target = targetSource.getTarget();

之後我們要獲得之前我們初始化的攔截器鏈。

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

如果沒有攔截器鏈(注意這個地方的攔截器實際上是對方法的增強操作),就直接執行相應的方法。

如果有攔截器的設定,那麼需要呼叫攔截器之後才呼叫目標物件的方法。

通過構造一個ReflectiveMethodInvocation來實現。

invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);

在攔截器鏈上執行相應的加強方法。

retVal = invocation.proceed();

這個invocation將我們的攔截器鏈(也就是一系列的通知器)進行了封裝,裡面定義了各個加強方法。

書上還有關於目標物件方法的呼叫

public static Object invokeJoinpointUsingReflection(Object target, Method method, Object[] args)
			throws Throwable {

		// Use reflection to invoke the method.
		try {
			ReflectionUtils.makeAccessible(method);
			return method.invoke(target, args);
		}
		catch (InvocationTargetException ex) {
			// Invoked method threw a checked exception.
			// We must rethrow it. The client won't see the interceptor.
			throw ex.getTargetException();
		}
		catch (IllegalArgumentException ex) {
			throw new AopInvocationException("AOP configuration seems to be invalid: tried calling method [" +
					method + "] on target [" + target + "]", ex);
		}
		catch (IllegalAccessException ex) {
			throw new AopInvocationException("Could not access method [" + method + "]", ex);
		}
	}

實際上我們可以看到還是呼叫這個jdk自身的反射機制

	return method.invoke(target, args);

AOP攔截器鏈的呼叫

關於AOP鏈的呼叫,就是AOP實現的核心部分了

我們需要分析一下這個proceed()方法。

首先我們沿著定義好的攔截器鏈進行處理

Object interceptorOrInterceptionAdvice =
				this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);

這個是為了遞迴查詢我們合適的攔截器而設定的。

接下來需要對攔截器進行動態匹配,也就是我們之前說的pointcut,匹配正確的切點進行正確的方法加強。

如果不匹配,那麼這個proceed方法就會被遞迴呼叫。

if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
			// Evaluate dynamic method matcher here: static part will already have
			// been evaluated and found to match.
			InterceptorAndDynamicMethodMatcher dm =
					(InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;
			if (dm.methodMatcher.matches(this.method, this.targetClass, this.arguments)) {
				return dm.interceptor.invoke(this);
			}
			else {
				// Dynamic matching failed.
				// Skip this interceptor and invoke the next in the chain.
				return proceed();
			}
		}

配置通知器

首先我們想要知道,在這個proceed()方法中的

Object interceptorOrInterceptionAdvice =
				this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);

這個攔截器鏈是怎麼獲取的呢。我們來看一下這個類的構造方法

protected ReflectiveMethodInvocation(
			Object proxy, Object target, Method method, Object[] arguments,
			Class<?> targetClass, List<Object> interceptorsAndDynamicMethodMatchers) {

		this.proxy = proxy;
		this.target = target;
		this.targetClass = targetClass;
		this.method = BridgeMethodResolver.findBridgedMethod(method);
		this.arguments = AopProxyUtils.adaptArgumentsIfNecessary(method, arguments);
		this.interceptorsAndDynamicMethodMatchers = interceptorsAndDynamicMethodMatchers;
	}

 這個引數的配置是我們傳入的一個入參。那麼回到整個攔截器鏈的配置過程,

invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);

一切就都明白了,我們把之前我們獲取到chain當做一個引數傳給了我們的invocation物件。

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

書上還為我們解釋了攔截器如何從AdvisedSupport獲得

public List<Object> getInterceptorsAndDynamicInterceptionAdvice(Method method, 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;
	}

取得攔截器的工作是由配置好的advisorChainFactory (DefaultAdvisorChainFactory物件)完成的

org.springframework.aop.framework.DefaultAdvisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice(
            Advised config, Method method, Class<?> targetClass)

在這個方法中,我們可以根據書中的程式碼進行分析。

首先我們的config持有了advisor鏈。至於為什麼持有了advisor鏈呢,我們需要對原先的程式碼進行一下追蹤。這個查詢過程需要去看。

在我們之前建立代理物件的時候,我有提到過這個方法。

org.springframework.aop.framework.ProxyCreatorSupport

protected final synchronized AopProxy createAopProxy() {
		if (!this.active) {
			activate();
		}
		return getAopProxyFactory().createAopProxy(this);
	}

這個類繼承了AdvisedSupport類,這就和之前的getInterceptorsAndDynamicInterceptionAdvice對應上了。

繼續向上查詢ProxyFactoryBean,在這個類中我們可以看到,它繼承了ProxyCreatorSupport。而我們在配置它的時候為它聲明瞭相應的advisors,這就是為什麼說config已經為我們配置好了相應的advisor鏈。實際上這一系列的this物件歸根到底都是內個最開始的ProxyFactoryBean物件。

具體的攔截器鏈的加入是通過AdvisorAdapterRegistry這個類來完成的。具體的程式碼我留作下一篇部落格解釋。