我們在上一篇文章中簡單的說了調用動態代理對象方法的過程,也說了AOP攔截器執行鏈的生成過程。我們接着說AOP對目標對象的攔截過程。下面的代碼是我們要分析的重點:
//proxy:生成的動態代理對象
//target:目標對象
//method:目標方法
//args:目標方法參數
//targetClass:目標類對象
//chain: AOP攔截器執行鏈 是一個MethodInterceptor的集合 這個鏈條的獲取過程參考我們上一篇文章的內容
invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
//開始執行AOP的攔截過程
retVal = invocation.proceed();
//構造ReflectiveMethodInvocation對象
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;
}
public Object proceed() throws Throwable {
// currentInterceptorIndex初始值爲 -1
// 如果執行到鏈條的末尾 則直接調用連接點方法 即 直接調用目標方法
if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
//下面會分析
return invokeJoinpoint();
}
//獲取集合中的 MethodInterceptor
Object interceptorOrInterceptionAdvice =
this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
//如果是InterceptorAndDynamicMethodMatcher類型
if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
InterceptorAndDynamicMethodMatcher dm =
(InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;
//這裏每一次都去匹配是否適用於這個目標方法
if (dm.methodMatcher.matches(this.method, this.targetClass, this.arguments)) {
//如果匹配則直接調用 MethodInterceptor的invoke方法
//注意這裏傳入的參數是this 我們下面看一下 ReflectiveMethodInvocation的類型
return dm.interceptor.invoke(this);
}
else {
//如果不適用於此目標方法 則繼續執行下一個鏈條
//遞歸調用
return proceed();
}
}
else {
//說明是適用於此目標方法的 直接調用 MethodInterceptor的invoke方法 傳入this即ReflectiveMethodInvocation實例
//傳入this進入 這樣就可以形成一個調用的鏈條了
return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
}
}
invokeJoinpoint方法
protected Object invokeJoinpoint() throws Throwable {
//this.target 目標對象
//this.method 目標方法
this.arguments 目標方法參數信息
return AopUtils.invokeJoinpointUsingReflection(this.target, this.method, this.arguments);
}
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);
}
}
ReflectiveMethodInvocation的UML類圖如下:
MethodInterceptorChain
OK,我們在proceed()這個方法中看到了AOP對於目標方法的一個攔截的過程,其中很重要的一個點是調用MethodInterceptor的invoke方法。我們先看一下MethodInterceptor的主要UML類圖(由於我們在開發中使用AspectJ註解的方式越來越多,所以我們這裏說的基本上都是基於AspectJ註解的):
從上圖我們也可以看到不同的通知其實相當於不同的MethodInterceptor類型。像前置通知會交給:MethodBeforeAdviceInterceptor來進行處理,後置通知是由AspectJAfterAdvice來處理的,環繞通知是由AspectJAroundAdvice來處理的。我們也挑幾個通知類型來說一下具體的調用過程。先說一下前置通知:
MethodBeforeAdviceInterceptor
//實現了MethodInterceptor接口
public class MethodBeforeAdviceInterceptor implements MethodInterceptor, Serializable {
//這個對象的獲取參考這個方法org.springframework.aop.aspectj.annotation.ReflectiveAspectJAdvisorFactory#getAdvice
//在之前的文章中有說過 不再描述
//這個MethodBeforeAdvice是AspectJMethodBeforeAdvice實例
private MethodBeforeAdvice advice;
public MethodBeforeAdviceInterceptor(MethodBeforeAdvice advice) {
Assert.notNull(advice, "Advice must not be null");
this.advice = advice;
}
@Override
public Object invoke(MethodInvocation mi) throws Throwable {
//這裏就會執行 前置通知的邏輯 這裏的advice是 AspectJMethodBeforeAdvice
this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis() );
//這裏傳入的MethodInvocation是ReflectiveMethodInvocation對象,即前面說的 傳入this
//相當於ReflectiveMethodInvocation.proceed() 遞歸調用。
return mi.proceed();
}
}
AspectJMethodBeforeAdvice#before代碼如下:
@Override
public void before(Method method, Object[] args, Object target) throws Throwable {
//這裏傳進來的目標對象、目標參數、目標方法都沒有用到
invokeAdviceMethod(getJoinPointMatch(), null, null);
}
protected JoinPointMatch getJoinPointMatch() {
//這裏從線程上下文中獲取MethodInvocation 看到這裏你也許會感到奇怪 跟着文章分析來看 我們沒有在設置過上下文的值啊
//這裏是怎麼獲取到MethodInvocation 的對象的呢?
//不知道你是否還記得 我們在獲取Advisor的時候 調用過這樣的一個方法org.springframework.aop.aspectj.AspectJProxyUtils#makeAdvisorChainAspectJCapableIfNecessary
//在這個方法中會有這樣的一段代碼
// if (foundAspectJAdvice && //!advisors.contains(ExposeInvocationInterceptor.ADVISOR)) {
// 如果獲取到了 Advisor 則向 Advisor集合中添加第一個元素 即 ExposeInvocationInterceptor.ADVISOR
//也就是說 我們的 Advisor列表中的第一個元素爲ExposeInvocationInterceptor.ADVISOR 它是一個DefaultPointcutAdvisor的實例
// 對於任何的目標方法都返回true 它的Advice是ExposeInvocationInterceptor
// advisors.add(0, ExposeInvocationInterceptor.ADVISOR);
// return true;
// }
// 這樣我們就不難理解了,在調用ReflectiveMethodInvocation#proceed的時候第一個調用的MethodInterceptor是ExposeInvocationInterceptor
//ExposeInvocationInterceptor的invoke方法的內容如下:
// public Object invoke(MethodInvocation mi) throws Throwable {
// 先取出舊的MethodInvocation的值
// MethodInvocation oldInvocation = invocation.get();
// 這裏設置新的 MethodInvocation 就是這裏了!!!
// invocation.set(mi);
// try {
// 遞歸調用
// return mi.proceed();
/// }
// finally {
// invocation.set(oldInvocation);
// }
// }
MethodInvocation mi = ExposeInvocationInterceptor.currentInvocation();
if (!(mi instanceof ProxyMethodInvocation)) {
throw new IllegalStateException("MethodInvocation is not a Spring ProxyMethodInvocation: " + mi);
}
//這裏主要是獲取 JoinPointMatch
return getJoinPointMatch((ProxyMethodInvocation) mi);
}
關於invokeAdviceMethod方法的內容我們在下一篇文章中繼續分析