1. 前言
我們知道aop實(shí)現(xiàn)的原理肯定是基于jdk動(dòng)態(tài)代理和cglib代理净刮,經(jīng)過生成代理對(duì)象琼腔,對(duì)命中切面的方法進(jìn)行增強(qiáng)更振。并將代理對(duì)象存放到ioc容器中,在其他對(duì)象需要的時(shí)候注入進(jìn)去, 那么肯定 需要通過解析類 去解析 并收集 Advisor對(duì)象集合 : 需要增強(qiáng)的目標(biāo)PointCut 以及 具體增強(qiáng)的邏輯Advice丧凤。 如果這個(gè)類是可以找到增強(qiáng)對(duì)象的,那么就應(yīng)該生成代理步脓。
2. 問題
2.1 生成的代理對(duì)象需要什么愿待?
首先 需要進(jìn)行 切面的收集和匹配
然后 把匹配到的切面 放入 生成的代理對(duì)象里,以便后續(xù)調(diào)用代理方法 來 決定調(diào)用哪個(gè)切面 來增強(qiáng)沪编。
我們來看下wrapIfNecessary方法里是如何 進(jìn)行切面的收集和匹配的呼盆。
3. Advisor增強(qiáng)對(duì)象的收集和匹配
3.1 Advisor增強(qiáng)對(duì)象的收集
該方法會(huì)先收集適合所有的Advisor增強(qiáng)對(duì)象年扩,并過濾出匹配當(dāng)前bean的Advisor對(duì)象
getAdvicesAndAdvisorsForBean
收集及匹配全在這
先看收集所有的切面findCandidateAdvisors()
這個(gè)方法是被他的子類重寫并調(diào)用的蚁廓,看子類AnnotationAwareAspectJAutoProxyCreator的該方法
spring自帶的advisors可以不看,我們直接看我們自己寫的@Aspect類
這里有兩個(gè)緩存
buildAspectJAdvisors方法里會(huì)先判斷緩存
第一次沒有厨幻,肯定先解析再獲取相嵌,我們看解析的邏輯
可以看到會(huì)遍歷spring容器里的每一個(gè)beanName,然后根據(jù)beanName獲取class,如果類上有Aspect注解,說明是需要解析的
將 beanFactory, beanName 封裝成一個(gè)獲取Advisor的工廠况脆,然后調(diào)用 this.advisorFactory.getAdvisors(factory) 去獲取advisors集合
3.1.1. 獲取沒有 @PointCut注解的方法集合
取出從獲取advisors工廠里取出beanClass, 去遍歷所有沒有@PointCut注解的方法饭宾,包含什么注解也沒有的方法
具體怎么獲取,也很簡(jiǎn)單格了,遍歷每一個(gè)方法看铆,如果沒有@Pointcut 注解就可以
3.1.2. 對(duì)要解析的方法集合排序
隨后會(huì)對(duì) 沒有@PointCut注解的方法集合進(jìn)行排序, 按照這個(gè)順序排序 : Around.class, Before.class, After.class, AfterReturning.class, AfterThrowing.class
METHOD_COMPARATOR 比較器 :
3.1.3. 遍歷沒有@PointCut注解的方法的集合盛末,開始創(chuàng)建Advisor對(duì)象
這里就開始要根據(jù)方法上面 aop相關(guān)的注解 來常見Advisor對(duì)象弹惦。
首先需要明確一點(diǎn),Advisor定義的 是 增強(qiáng)的目標(biāo) 與 增強(qiáng)的邏輯悄但,
- 增強(qiáng)的目標(biāo) 則是Pointcut對(duì)象定義的
- 增強(qiáng)的邏輯 則是Advice對(duì)象定義的
所以棠隐,Advisor 必須要包含Pointcut對(duì)象和 Advice對(duì)象。
3.1.3.1. Pointcut接口介紹
基于表達(dá)式的PointCut實(shí)現(xiàn)類是 AspectJExpressionPointcut類檐嚣,它除了多持有一個(gè)表達(dá)式外助泽,還會(huì)實(shí)現(xiàn)的 Pointcut接口。
public interface Pointcut {
ClassFilter getClassFilter();
MethodMatcher getMethodMatcher();
Pointcut TRUE = TruePointcut.INSTANCE;
}
需要重寫getClassFilter()來提供ClassFilter, ClassFilter是一個(gè)接口嚎京,重寫matches方法嗡贺,來定義是否與類匹配
@FunctionalInterface
public interface ClassFilter {
// 定義是否與類匹配
boolean matches(Class<?> clazz);
ClassFilter TRUE = TrueClassFilter.INSTANCE;
}
重寫 getMethodMatcher()方法 來提供MethodMatcher 對(duì)象, MethodMatcher也是一個(gè)接口
public interface MethodMatcher {
// 定義是否與類匹配
boolean matches(Method method, Class<?> targetClass);
boolean isRuntime();
// 定義是否與方法匹配
boolean matches(Method method, Class<?> targetClass, Object... args);
MethodMatcher TRUE = TrueMethodMatcher.INSTANCE;
}
這里AspectJExpressionPointcut類鞍帝,自己實(shí)現(xiàn)了ClassFilter接口诫睬,和IntroductionAwareMethodMatcher接口,可以看到實(shí)現(xiàn)至Pointcut接口接口的兩個(gè)方法 返回的都是自身膜眠。
這里先這樣,后面匹配的時(shí)候 再看這兩個(gè)方法里具體的匹配邏輯架谎。
3.1.3.2. PointCut對(duì)象的創(chuàng)建
進(jìn)入 getAdvisor(Method candidateAdviceMethod, MetadataAwareAspectInstanceFactory aspectInstanceFactory,
int declarationOrderInAspect, String aspectName) 方法
進(jìn)入 getPointcut方法炸宵,這里先獲取Pointcut.class, Around.class, Before.class, After.class, AfterReturning.class, AfterThrowing.class 這幾個(gè)注解,匹配到就返回
不可能獲取到@Pointcut注解
其實(shí)這里是不可能獲取到 @Pointcut ,因?yàn)榍懊?遍歷的整個(gè)方法的集合 就已經(jīng)是排除掉了 @Pointcut注解的方法
獲取需要遍歷的整個(gè)方法集合代碼 
getPointcut方法
注解獲取到Around.class, Before.class, After.class, AfterReturning.class, AfterThrowing.class注解里的其中任意一個(gè)谷扣,獲取注解里的pointcutExpression屬性土全,以及目標(biāo)類的class對(duì)象,設(shè)置到創(chuàng)建的AspectJExpressionPointcut對(duì)象里会涎,并返回
到這里pointCut對(duì)象已經(jīng)創(chuàng)建完成裹匙,其實(shí)并不會(huì)去 掃描有@PointCut注解的方法,只是通過Around.class, Before.class, After.class, AfterReturning.class, AfterThrowing.class里的pointcut屬性末秃,去指向@PointCut注解的方法概页,到時(shí)候可以 根據(jù)這個(gè) 去找 @PointCut注解的方法,再去找@PointCut里面具體配置的表達(dá)式,明確切點(diǎn)练慕。
3.1.3.3. Advice對(duì)象的創(chuàng)建
代碼回到入 getAdvisor(Method candidateAdviceMethod, MetadataAwareAspectInstanceFactory aspectInstanceFactory,
int declarationOrderInAspect, String aspectName) 方法惰匙。
會(huì)new出InstantiationModelAwarePointcutAdvisorImpl對(duì)象, 傳入AspectJExpressionPointcut對(duì)象到構(gòu)造方法里
InstantiationModelAwarePointcutAdvisorImpl構(gòu)造方法
會(huì)先存PointCut對(duì)象以及原生Method對(duì)象,再在instantiateAdvice方法里創(chuàng)建Advice對(duì)象
instantiateAdvice方法里創(chuàng)建Advice對(duì)象
首先從原生method方法铃将,取出 Around.class, Before.class, After.class, AfterReturning.class, AfterThrowing.class 這五個(gè)注解中的一個(gè)(一個(gè)方法只能取到其中一個(gè)注解项鬼,一般只會(huì)配一個(gè))
再判斷注解,根據(jù)注解的不同劲阎,創(chuàng)建的Advice對(duì)象也不同
可以看到注解與創(chuàng)建的AspectJAroundAdvice類有如下對(duì)應(yīng)關(guān)系
注解 | Aavice實(shí)現(xiàn)類 |
---|---|
@Around | AspectJAroundAdvice |
@Before | AspectJMethodBeforeAdvice |
@After | AspectJAfterAdvice |
@AfterReturning | AspectJAfterReturningAdvice |
@AfterThrowing | AspectJAfterThrowingAdvice |
MethodInterceptor接口
其中AspectJAroundAdvice,AspectJMethodBeforeAdvice,AspectJAfterAdvice這三個(gè)類是實(shí)現(xiàn)MethodInterceptor接口的
實(shí)現(xiàn)的invoke方法 持有 整個(gè)aop切面調(diào)用鏈上下文對(duì)象绘盟,以完成 切面調(diào)用鏈的回調(diào),繼續(xù)調(diào)用剩下的的 切面悯仙。
@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這兩個(gè)切面沒有龄毡,到時(shí)候aop調(diào)用的時(shí)候,會(huì)對(duì)這兩個(gè)切面類進(jìn)行 MethodInterceptor類型適配雁比,以保證 調(diào)用和調(diào)用鏈 傳遞邏輯的 統(tǒng)一稚虎。
最終返回 各自的切面對(duì)象。
Advisor對(duì)象創(chuàng)建完成偎捎,存入緩存
直到所有方法都掃描完成蠢终,對(duì)應(yīng)的Advisor對(duì)象 也創(chuàng)建成功,都存入緩存: beanName -> 對(duì)應(yīng)類解析出來的 advisors
至此, 當(dāng)容器內(nèi)所有的beanName都遍歷完成茴她,對(duì)應(yīng)的class 通過解析寻拂、創(chuàng)建出來的Advisor對(duì)象全部 收集完畢。