
1. 前言
我們知道aop實現(xiàn)的原理肯定是基于jdk動態(tài)代理和cglib代理,經過生成代理對象,對命中切面的方法進行增強。并將代理對象存放到ioc容器中,在其他對象需要的時候注入進去, 那么肯定 需要通過解析類 去解析 并收集 Advisor對象集合 : 需要增強的目標PointCut 以及 具體增強的邏輯Advice。 如果這個類是可以找到增強對象的,那么就應該生成代理。
2. 問題
2.1 生成的代理對象需要什么?
首先 需要進行 切面的收集和匹配
然后 把匹配到的切面 放入 生成的代理對象里,以便后續(xù)調用代理方法 來 決定調用哪個切面 來增強。
我們來看下wrapIfNecessary方法里是如何 進行切面的收集和匹配的。

3. Advisor增強對象的收集和匹配
3.1 Advisor增強對象的收集
該方法會先收集適合所有的Advisor增強對象,并過濾出匹配當前bean的Advisor對象

getAdvicesAndAdvisorsForBean

收集及匹配全在這

先看收集所有的切面findCandidateAdvisors()
這個方法是被他的子類重寫并調用的,看子類AnnotationAwareAspectJAutoProxyCreator的該方法


spring自帶的advisors可以不看,我們直接看我們自己寫的@Aspect類

這里有兩個緩存

buildAspectJAdvisors方法里會先判斷緩存

第一次沒有,肯定先解析再獲取,我們看解析的邏輯
可以看到會遍歷spring容器里的每一個beanName,然后根據(jù)beanName獲取class,如果類上有Aspect注解,說明是需要解析的
將 beanFactory, beanName 封裝成一個獲取Advisor的工廠,然后調用 this.advisorFactory.getAdvisors(factory) 去獲取advisors集合

3.1.1. 獲取沒有 @PointCut注解的方法集合
取出從獲取advisors工廠里取出beanClass, 去遍歷所有沒有@PointCut注解的方法,包含什么注解也沒有的方法

具體怎么獲取,也很簡單,遍歷每一個方法,如果沒有@Pointcut 注解就可以

3.1.2. 對要解析的方法集合排序
隨后會對 沒有@PointCut注解的方法集合進行排序, 按照這個順序排序 : Around.class, Before.class, After.class, AfterReturning.class, AfterThrowing.class

METHOD_COMPARATOR 比較器 :

3.1.3. 遍歷沒有@PointCut注解的方法的集合,開始創(chuàng)建Advisor對象
這里就開始要根據(jù)方法上面 aop相關的注解 來常見Advisor對象。
首先需要明確一點,Advisor定義的 是 增強的目標 與 增強的邏輯,
- 增強的目標 則是Pointcut對象定義的
- 增強的邏輯 則是Advice對象定義的
所以,Advisor 必須要包含Pointcut對象和 Advice對象。

3.1.3.1. Pointcut接口介紹
基于表達式的PointCut實現(xiàn)類是 AspectJExpressionPointcut類,它除了多持有一個表達式外,還會實現(xiàn)的 Pointcut接口。
public interface Pointcut {
ClassFilter getClassFilter();
MethodMatcher getMethodMatcher();
Pointcut TRUE = TruePointcut.INSTANCE;
}
需要重寫getClassFilter()來提供ClassFilter, ClassFilter是一個接口,重寫matches方法,來定義是否與類匹配
@FunctionalInterface
public interface ClassFilter {
// 定義是否與類匹配
boolean matches(Class<?> clazz);
ClassFilter TRUE = TrueClassFilter.INSTANCE;
}
重寫 getMethodMatcher()方法 來提供MethodMatcher 對象, MethodMatcher也是一個接口
public interface MethodMatcher {
// 定義是否與類匹配
boolean matches(Method method, Class<?> targetClass);
boolean isRuntime();
// 定義是否與方法匹配
boolean matches(Method method, Class<?> targetClass, Object... args);
MethodMatcher TRUE = TrueMethodMatcher.INSTANCE;
}
這里AspectJExpressionPointcut類,自己實現(xiàn)了ClassFilter接口,和IntroductionAwareMethodMatcher接口,可以看到實現(xiàn)至Pointcut接口接口的兩個方法 返回的都是自身。


這里先這樣,后面匹配的時候 再看這兩個方法里具體的匹配邏輯。
3.1.3.2. PointCut對象的創(chuàng)建
進入 getAdvisor(Method candidateAdviceMethod, MetadataAwareAspectInstanceFactory aspectInstanceFactory,
int declarationOrderInAspect, String aspectName) 方法

進入 getPointcut方法,這里先獲取Pointcut.class, Around.class, Before.class, After.class, AfterReturning.class, AfterThrowing.class 這幾個注解,匹配到就返回
不可能獲取到@Pointcut注解
其實這里是不可能獲取到 @Pointcut ,因為前面 遍歷的整個方法的集合 就已經是排除掉了 @Pointcut注解的方法
獲取需要遍歷的整個方法集合代碼 
getPointcut方法
注解獲取到Around.class, Before.class, After.class, AfterReturning.class, AfterThrowing.class注解里的其中任意一個,獲取注解里的pointcutExpression屬性,以及目標類的class對象,設置到創(chuàng)建的AspectJExpressionPointcut對象里,并返回

到這里pointCut對象已經創(chuàng)建完成,其實并不會去 掃描有@PointCut注解的方法,只是通過Around.class, Before.class, After.class, AfterReturning.class, AfterThrowing.class里的pointcut屬性,去指向@PointCut注解的方法,到時候可以 根據(jù)這個 去找 @PointCut注解的方法,再去找@PointCut里面具體配置的表達式,明確切點。
3.1.3.3. Advice對象的創(chuàng)建
代碼回到入 getAdvisor(Method candidateAdviceMethod, MetadataAwareAspectInstanceFactory aspectInstanceFactory,
int declarationOrderInAspect, String aspectName) 方法。
會new出InstantiationModelAwarePointcutAdvisorImpl對象, 傳入AspectJExpressionPointcut對象到構造方法里

InstantiationModelAwarePointcutAdvisorImpl構造方法
會先存PointCut對象以及原生Method對象,再在instantiateAdvice方法里創(chuàng)建Advice對象

instantiateAdvice方法里創(chuàng)建Advice對象

首先從原生method方法,取出 Around.class, Before.class, After.class, AfterReturning.class, AfterThrowing.class 這五個注解中的一個(一個方法只能取到其中一個注解,一般只會配一個)

再判斷注解,根據(jù)注解的不同,創(chuàng)建的Advice對象也不同

可以看到注解與創(chuàng)建的AspectJAroundAdvice類有如下對應關系
| 注解 | Aavice實現(xiàn)類 |
|---|---|
| @Around | AspectJAroundAdvice |
| @Before | AspectJMethodBeforeAdvice |
| @After | AspectJAfterAdvice |
| @AfterReturning | AspectJAfterReturningAdvice |
| @AfterThrowing | AspectJAfterThrowingAdvice |
MethodInterceptor接口
其中AspectJAroundAdvice,AspectJMethodBeforeAdvice,AspectJAfterAdvice這三個類是實現(xiàn)MethodInterceptor接口的
實現(xiàn)的invoke方法 持有 整個aop切面調用鏈上下文對象,以完成 切面調用鏈的回調,繼續(xù)調用剩下的的 切面。
@FunctionalInterface
public interface MethodInterceptor extends Interceptor {
Object invoke(MethodInvocation invocation) throws Throwable;
}
public class AspectJAfterAdvice extends AbstractAspectJAdvice
implements MethodInterceptor, AfterAdvice, Serializable {
@Override
public Object invoke(MethodInvocation mi) throws Throwable {
try {
return mi.proceed();
}
finally {
invokeAdviceMethod(getJoinPointMatch(), null, null);
}
}
}
public class AspectJMethodBeforeAdvice extends AbstractAspectJAdvice implements MethodBeforeAdvice, Serializable {
public Object invoke(){
// 繼承的父類 AbstractAspectJAdvice的invoke
}
@Override
public void before(Method method, Object[] args, @Nullable Object target) throws Throwable {
invokeAdviceMethod(getJoinPointMatch(), null, null);
}
}
public class AspectJAfterAdvice extends AbstractAspectJAdvice
implements MethodInterceptor, AfterAdvice, Serializable {
@Override
public Object invoke(MethodInvocation mi) throws Throwable {
try {
return mi.proceed();
}
finally {
invokeAdviceMethod(getJoinPointMatch(), null, null);
}
}
}
而AspectJAfterReturningAdvice,AspectJAfterThrowingAdvice這兩個切面沒有,到時候aop調用的時候,會對這兩個切面類進行 MethodInterceptor類型適配,以保證 調用和調用鏈 傳遞邏輯的 統(tǒng)一。
最終返回 各自的切面對象。

Advisor對象創(chuàng)建完成,存入緩存
直到所有方法都掃描完成,對應的Advisor對象 也創(chuàng)建成功,都存入緩存: beanName -> 對應類解析出來的 advisors

至此, 當容器內所有的beanName都遍歷完成,對應的class 通過解析、創(chuàng)建出來的Advisor對象全部 收集完畢。
