目錄
1. 說明
在IOC容器中獲取目標組件的時候,實際獲取到的是增強後的代理組件,執行目標方法的時候,也是由此代理組件去執行;
public static void main(String[] args) throws Exception {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfigForAop.class);
//獲取到的是增強後的代理組件
Calculator calculator = applicationContext.getBean(Calculator.class);
//代理組件執行目標方法
System.out.println("結果: " + calculator.div(10, 0));
applicationContext.close();
}
2. 目標方法執行
2.1 代理組件執行目標方法流程
代理組件中保存了目標組件的詳細信息,包括目標類的增強器列表,執行流程如下;
- 根據ProxyFactory對象獲取將增強器轉成要執行的目標方法攔截器鏈;
- 如果沒有攔截器鏈,直接執行目標方法;
- 如果有攔截器鏈,把需要執行的目標對象,目標方法,攔截器鏈等信息傳入創建一個 CglibMethodInvocation 對象,
並調用 Object retVal = mi.proceed(); - 執行攔截器鏈;
2.2 增強器轉成目標方法的攔截器鏈
執行目標方法,進入org.springframework.aop.framework.CglibAopProxy.DynamicAdvisedInterceptor.intercept(Object, Method, Object[], MethodProxy)中:
@Override
public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
Object oldProxy = null;
boolean setProxyContext = false;
Class<?> targetClass = null;
Object target = null;
try {
if (this.advised.exposeProxy) {
// Make invocation available if necessary.
oldProxy = AopContext.setCurrentProxy(proxy);
setProxyContext = true;
}
// May be null. Get as late as possible to minimize the time we
// "own" the target, in case it comes from a pool...
target = getTarget();
if (target != null) {
targetClass = target.getClass();
}
//將增強器轉成目標方法的攔截器鏈
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
Object retVal;
// Check whether we only have one InvokerInterceptor: that is,
// no real advice, but just reflective invocation of the target.
if (chain.isEmpty() && Modifier.isPublic(method.getModifiers())) {
// We can skip creating a MethodInvocation: just invoke the target directly.
// Note that the final invoker must be an InvokerInterceptor, so we know
// it does nothing but a reflective operation on the target, and no hot
// swapping or fancy proxying.
Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
retVal = methodProxy.invoke(target, argsToUse);
}
else {
// We need to create a method invocation...
// 創建CglibMethodInvocation,執行目標方法和攔截器鏈
retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed();
}
retVal = processReturnType(proxy, target, method, retVal);
return retVal;
}
finally {
if (target != null) {
releaseTarget(target);
}
if (setProxyContext) {
// Restore old proxy.
AopContext.setCurrentProxy(oldProxy);
}
}
}
在轉成攔截器鏈的過程中,如果是MethodInterceptor,直接加入到集合中,如果不是,使用AdvisorAdapter將增強器轉爲MethodInterceptor;
@Override
public MethodInterceptor[] getInterceptors(Advisor advisor) throws UnknownAdviceTypeException {
List<MethodInterceptor> interceptors = new ArrayList<MethodInterceptor>(3);
Advice advice = advisor.getAdvice();
// 如果是MethodInterceptor,則直接加入集合
if (advice instanceof MethodInterceptor) {
interceptors.add((MethodInterceptor) advice);
}
//如果不是,使用AdvisorAdapter將增強器轉爲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[interceptors.size()]);
}
得到的攔截器鏈集合的結果如下:
一個默認的ExposeInvocationInterceptor 和 4個增強器;
2.3 攔截器鏈和目標方法的執行
具體執行方法在org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(),代碼如下:
@Override
public Object proceed() throws Throwable {
// We start with an index of -1 and increment early.
// 初始索引=-1
if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
// 當interceptorsAndDynamicMethodMatchers爲空或者 currentInterceptorIndex=interceptorsAndDynamicMethodMatchers.size()-1的時候,
// 直接調用目標方法, invokeJoinpoint()裏面實際是執行 method.invoke(target, args);
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;
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();
}
}
else {
// It's an interceptor, so we just invoke it: The pointcut will have
// been evaluated statically before this object was constructed.
// 調用攔截器的invoke方法;各個攔截器裏面的執行其實是 調用自定義代碼邏輯和還是調用該方法proceed();
return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
}
}
攔截器和目標方法的執行流程如下圖:
3. 總結
目標方法執行流程如下:
- 代理對象執行目標方法;
- CglibAopProxy.intercept();
- 得到目標方法的攔截器鏈(增強器包裝成攔截器MethodInterceptor);
- 利用攔截器的鏈式機制,依次進入每一個攔截器進行執行;
- 效果:
- 正常執行:前置通知-》目標方法-》後置通知-》返回通知;
- 出現異常:前置通知-》目標方法-》後置通知-》異常通知
- 執行結束;