Spring AOP的實現:Spring AOP攔截器呼叫的實現
上次我說到關於ProxyFactoryBean物件的getObject方法返回了一個代理物件。剩下的AOP實現過程就和jdk的代理模式相同。通過呼叫這個代理物件的方法(這個方法和目標物件是相同的),但是實際上是呼叫了invoke方法,通過反射來實現方法的增強。
關於jdk如何實現代理模式的反編譯,底層的程式碼實現過程可以在這個部落格中檢視
https://blog.csdn.net/u013815218/article/details/52562536(轉載)
目錄
現在我們來看上次說的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這個類來完成的。具體的程式碼我留作下一篇部落格解釋。