1.前言
從本篇文章開(kāi)始,我將會(huì)對(duì) Spring AOP 部分的源碼進(jìn)行分析。本文是 Spring AOP 源碼分析系列文章的第二篇,本文主要分析 Spring AOP 是如何為目標(biāo) bean篩選出合適的通知器(Advisor)。
2.源碼分析
2.1AOP入口分析
在導(dǎo)讀一文中,我已經(jīng)說(shuō)過(guò) Spring AOP 是在何處向目標(biāo) bean 中織入通知(Advice)的。也說(shuō)過(guò) Spring 是如何將 AOP 和 IOC 模塊整合到一起的,即通過(guò)拓展點(diǎn) BeanPostProcessor 接口。Spring AOP 抽象代理創(chuàng)建器實(shí)現(xiàn)了 BeanPostProcessor 接口,并在 bean 初始化后置處理過(guò)程中向 bean 中織入通知。下面我們就來(lái)看看相關(guān)源碼,如下:
public abstract class AbstractAutoProxyCreator extends ProxyProcessorSupport
implements SmartInstantiationAwareBeanPostProcessor, BeanFactoryAware {
@Override
/** bean 初始化后置處理方法 */
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if (bean != null) {
Object cacheKey = getCacheKey(bean.getClass(), beanName);
if (!this.earlyProxyReferences.contains(cacheKey)) {
// 如果需要,為 bean 生成代理對(duì)象
return wrapIfNecessary(bean, beanName, cacheKey);
}
}
return bean;
}
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
if (beanName != null && this.targetSourcedBeans.contains(beanName)) {
return bean;
}
if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
return bean;
}
/*
* 如果是基礎(chǔ)設(shè)施類(lèi)(Pointcut、Advice、Advisor 等接口的實(shí)現(xiàn)類(lèi)),或是應(yīng)該跳過(guò)的類(lèi),
* 則不應(yīng)該生成代理,此時(shí)直接返回 bean
*/
if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
// 將 <cacheKey, FALSE> 鍵值對(duì)放入緩存中,供上面的 if 分支使用
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
}
// 為目標(biāo) bean 查找合適的通知器
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
/*
* 若 specificInterceptors != null,即 specificInterceptors != DO_NOT_PROXY,
* 則為 bean 生成代理對(duì)象,否則直接返回 bean
*/
if (specificInterceptors != DO_NOT_PROXY) {
this.advisedBeans.put(cacheKey, Boolean.TRUE);
// 創(chuàng)建代理
Object proxy = createProxy(
bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
this.proxyTypes.put(cacheKey, proxy.getClass());
/*
* 返回代理對(duì)象,此時(shí) IOC 容器輸入 bean,得到 proxy。此時(shí),
* beanName 對(duì)應(yīng)的 bean 是代理對(duì)象,而非原始的 bean
*/
return proxy;
}
this.advisedBeans.put(cacheKey, Boolean.FALSE);
// specificInterceptors = null,直接返回 bean
return bean;
}
}
以上就是 Spring AOP 創(chuàng)建代理對(duì)象的入口方法分析,過(guò)程比較簡(jiǎn)單,這里簡(jiǎn)單總結(jié)一下:
1.若 bean 是 AOP 基礎(chǔ)設(shè)施類(lèi)型,則直接返回
2.為 bean 查找合適的通知器
3.如果通知器數(shù)組不為空,則為 bean 生成代理對(duì)象,并返回該對(duì)象
4.若數(shù)組為空,則返回原始 bean
上面的流程看起來(lái)并不復(fù)雜,不過(guò)不要被表象所迷糊,以上流程不過(guò)是冰山一角。
2.2篩選合適的通知器
在向目標(biāo) bean 中織入通知之前,我們先要為 bean 篩選出合適的通知器(通知器持有通知)。如何篩選呢?方式由很多,比如我們可以通過(guò)正則表達(dá)式匹配方法名,當(dāng)然更多的時(shí)候用的是 AspectJ 表達(dá)式進(jìn)行匹配。那下面我們就來(lái)看一下使用 AspectJ 表達(dá)式篩選通知器的過(guò)程,如下:
protected Object[] getAdvicesAndAdvisorsForBean(Class<?> beanClass, String beanName, TargetSource targetSource) {
// 查找合適的通知器
List<Advisor> advisors = findEligibleAdvisors(beanClass, beanName);
if (advisors.isEmpty()) {
return DO_NOT_PROXY;
}
return advisors.toArray();
}
protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {
// 查找所有的通知器
List<Advisor> candidateAdvisors = findCandidateAdvisors();
/*
* 篩選可應(yīng)用在 beanClass 上的 Advisor,通過(guò) ClassFilter 和 MethodMatcher
* 對(duì)目標(biāo)類(lèi)和方法進(jìn)行匹配
*/
List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
// 拓展操作
extendAdvisors(eligibleAdvisors);
if (!eligibleAdvisors.isEmpty()) {
eligibleAdvisors = sortAdvisors(eligibleAdvisors);
}
return eligibleAdvisors;
}
如上,Spring 先查詢(xún)出所有的通知器,然后再調(diào)用 findAdvisorsThatCanApply 對(duì)通知器進(jìn)行篩選。在下面幾節(jié)中,我將分別對(duì) findCandidateAdvisors 和 findAdvisorsThatCanApply 兩個(gè)方法進(jìn)行分析,繼續(xù)往下看吧。
2.2.1 兩種配置方式
Spring 提供了兩種配置 AOP 的方式,一種是通過(guò) XML 進(jìn)行配置,另一種是注解。對(duì)于兩種配置方式,Spring 的處理邏輯是不同的。對(duì)于 XML 類(lèi)型的配置,比如下面的配置:
<!-- 目標(biāo) bean -->
<bean id="hello" class="xyz.coolblog.aop.Hello"/>
<aop:aspectj-autoproxy/>
<!-- 普通 bean,包含 AOP 切面邏輯 -->
<bean id="aopCode" class="xyz.coolblog.aop.AopCode"/>
<!-- 由 @Aspect 注解修飾的切面類(lèi) -->
<bean id="annotationAopCode" class="xyz.coolblog.aop.AnnotationAopCode"/>
<aop:config>
<aop:aspect ref="aopCode">
<aop:pointcut id="helloPointcut" expression="execution(* xyz.coolblog.aop.*.hello*(..))" />
<aop:before method="before" pointcut-ref="helloPointcut"/>
<aop:after method="after" pointcut-ref="helloPointcut"/>
</aop:aspect>
</aop:config>
Spring 會(huì)將上的配置解析為下面的結(jié)果:

如上圖所示,紅框中對(duì)應(yīng)的是普通的 bean 定義,比如 <bean id="hello" .../>、<bean id="annotationAopCode" .../>、<bean id="appCode" .../> 等配置。黃色框中的則是切點(diǎn)的定義,類(lèi)型為 AspectJExpressionPointcut,對(duì)應(yīng) <aop:pointcut id="helloPointcut" .../> 配置。那綠色框中的結(jié)果對(duì)應(yīng)的是什么配置呢?目前僅剩下兩個(gè)配置沒(méi)說(shuō),所以對(duì)應(yīng) <aop:before .../> 和 <aop:after .../> 配置,類(lèi)型為 AspectJPointcutAdvisor。這里請(qǐng)大家注意,由 @Aspect 注解修飾的 AnnotationAopCode 也是普通類(lèi)型的 bean,該 bean 會(huì)在查找通知器的過(guò)程中被解析,并被構(gòu)建為一個(gè)或多個(gè) Advisor。
上面講解了 Spring AOP 兩種配置的處理方式,算是為下面的源碼分析做鋪墊?,F(xiàn)在鋪墊完畢,我們就來(lái)分析一下源碼吧。如下:
2.2.2 findCandidateAdvisors 方法分析(xml配置方式獲取)
我們先來(lái)看一下 AbstractAdvisorAutoProxyCreator 中 findCandidateAdvisors 方法的定義,如下:
public abstract class AbstractAdvisorAutoProxyCreator extends AbstractAutoProxyCreator {
private BeanFactoryAdvisorRetrievalHelper advisorRetrievalHelper;
//...
protected List<Advisor> findCandidateAdvisors() {
return this.advisorRetrievalHelper.findAdvisorBeans();
}
//...
}
從上面的源碼中可以看出,AbstractAdvisorAutoProxyCreator 中的 findCandidateAdvisors 是個(gè)空殼方法,所有邏輯封裝在了一個(gè) BeanFactoryAdvisorRetrievalHelper 的 findAdvisorBeans 方法中。這里大家可以仔細(xì)看一下類(lèi)名 BeanFactoryAdvisorRetrievalHelper 和方法 findAdvisorBeans,兩個(gè)名字其實(shí)已經(jīng)描述出他們的職責(zé)了。BeanFactoryAdvisorRetrievalHelper 可以理解為從 bean 容器中獲取 Advisor 的幫助類(lèi),findAdvisorBeans 則可理解為查找 Advisor 類(lèi)型的 bean。所以即使不看 findAdvisorBeans 方法的源碼,我們也可從方法名上推斷出它要做什么,即從 bean 容器中將 Advisor 類(lèi)型的 bean 查找出來(lái)。下面我來(lái)分析一下這個(gè)方法的源碼,如下:
public List<Advisor> findAdvisorBeans() {
String[] advisorNames = null;
synchronized (this) {
// cachedAdvisorBeanNames 是 advisor 名稱(chēng)的緩存
advisorNames = this.cachedAdvisorBeanNames;
/*
* 如果 cachedAdvisorBeanNames 為空,這里到容器中查找,
* 并設(shè)置緩存,后續(xù)直接使用緩存即可
*/
if (advisorNames == null) {
// 從容器中查找 Advisor 類(lèi)型 bean 的名稱(chēng)
advisorNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
this.beanFactory, Advisor.class, true, false);
// 設(shè)置緩存
this.cachedAdvisorBeanNames = advisorNames;
}
}
if (advisorNames.length == 0) {
return new LinkedList<Advisor>();
}
List<Advisor> advisors = new LinkedList<Advisor>();
// 遍歷 advisorNames
for (String name : advisorNames) {
if (isEligibleBean(name)) {
// 忽略正在創(chuàng)建中的 advisor bean
if (this.beanFactory.isCurrentlyInCreation(name)) {
if (logger.isDebugEnabled()) {
logger.debug("Skipping currently created advisor '" + name + "'");
}
}
else {
try {
/*
* 調(diào)用 getBean 方法從容器中獲取名稱(chēng)為 name 的 bean,
* 并將 bean 添加到 advisors 中
*/
advisors.add(this.beanFactory.getBean(name, Advisor.class));
}
catch (BeanCreationException ex) {
Throwable rootCause = ex.getMostSpecificCause();
if (rootCause instanceof BeanCurrentlyInCreationException) {
BeanCreationException bce = (BeanCreationException) rootCause;
if (this.beanFactory.isCurrentlyInCreation(bce.getBeanName())) {
if (logger.isDebugEnabled()) {
logger.debug("Skipping advisor '" + name +
"' with dependency on currently created bean: " + ex.getMessage());
}
continue;
}
}
throw ex;
}
}
}
}
return advisors;
}
以上就是從容器中查找 Advisor 類(lèi)型的 bean 所有的邏輯,代碼雖然有點(diǎn)長(zhǎng),但并不復(fù)雜。主要做了兩件事情:
1.從容器中查找所有類(lèi)型為 Advisor 的 bean 對(duì)應(yīng)的名稱(chēng)
2.遍歷 advisorNames,并從容器中獲取對(duì)應(yīng)的 bean
看完上面的分析,我們繼續(xù)來(lái)分析一下 @Aspect 注解的解析過(guò)程。
2.2.3 buildAspectJAdvisors 方法分析(注解方式獲?。?/h3>
AnnotationAwareAspectJAutoProxyCreator 覆寫(xiě)了父類(lèi)的方法 findCandidateAdvisors,并增加了一步操作,即解析 @Aspect 注解,并構(gòu)建成通知器。下面我先來(lái)分析一下父類(lèi)中的 findCandidateAdvisors 方法的邏輯,然后再來(lái)分析 buildAspectJAdvisors 方法邏的輯
public class AnnotationAwareAspectJAutoProxyCreator extends AspectJAwareAdvisorAutoProxyCreator {
//...
@Override
protected List<Advisor> findCandidateAdvisors() {
// 調(diào)用父類(lèi)方法從容器中查找所有的通知器
List<Advisor> advisors = super.findCandidateAdvisors();
// 解析 @Aspect 注解,并構(gòu)建通知器
advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors());
return advisors;
}
//...
}
與上一節(jié)的內(nèi)容相比,解析 @Aspect 注解的過(guò)程還是比較復(fù)雜的,需要一些耐心去看。下面我們開(kāi)始分析 buildAspectJAdvisors 方法的源碼,如下:
public List<Advisor> buildAspectJAdvisors() {
List<String> aspectNames = this.aspectBeanNames;
if (aspectNames == null) {
synchronized (this) {
aspectNames = this.aspectBeanNames;
if (aspectNames == null) {
List<Advisor> advisors = new LinkedList<Advisor>();
aspectNames = new LinkedList<String>();
// 從容器中獲取所有 bean 的名稱(chēng)
String[] beanNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
this.beanFactory, Object.class, true, false);
// 遍歷 beanNames
for (String beanName : beanNames) {
if (!isEligibleBean(beanName)) {
continue;
}
// 根據(jù) beanName 獲取 bean 的類(lèi)型
Class<?> beanType = this.beanFactory.getType(beanName);
if (beanType == null) {
continue;
}
// 檢測(cè) beanType 是否包含 Aspect 注解
if (this.advisorFactory.isAspect(beanType)) {
aspectNames.add(beanName);
AspectMetadata amd = new AspectMetadata(beanType, beanName);
if (amd.getAjType().getPerClause().getKind() == PerClauseKind.SINGLETON) {
MetadataAwareAspectInstanceFactory factory =
new BeanFactoryAspectInstanceFactory(this.beanFactory, beanName);
// 獲取通知器
List<Advisor> classAdvisors = this.advisorFactory.getAdvisors(factory);
if (this.beanFactory.isSingleton(beanName)) {
this.advisorsCache.put(beanName, classAdvisors);
}
else {
this.aspectFactoryCache.put(beanName, factory);
}
advisors.addAll(classAdvisors);
}
else {
if (this.beanFactory.isSingleton(beanName)) {
throw new IllegalArgumentException("Bean with name '" + beanName +
"' is a singleton, but aspect instantiation model is not singleton");
}
MetadataAwareAspectInstanceFactory factory =
new PrototypeAspectInstanceFactory(this.beanFactory, beanName);
this.aspectFactoryCache.put(beanName, factory);
advisors.addAll(this.advisorFactory.getAdvisors(factory));
}
}
}
this.aspectBeanNames = aspectNames;
return advisors;
}
}
}
if (aspectNames.isEmpty()) {
return Collections.emptyList();
}
List<Advisor> advisors = new LinkedList<Advisor>();
for (String aspectName : aspectNames) {
List<Advisor> cachedAdvisors = this.advisorsCache.get(aspectName);
if (cachedAdvisors != null) {
advisors.addAll(cachedAdvisors);
}
else {
MetadataAwareAspectInstanceFactory factory = this.aspectFactoryCache.get(aspectName);
advisors.addAll(this.advisorFactory.getAdvisors(factory));
}
}
return advisors;
}
上面就是 buildAspectJAdvisors 的代碼,看起來(lái)比較長(zhǎng)。代碼比較多,我們關(guān)注重點(diǎn)的方法調(diào)用即可。在進(jìn)行后續(xù)的分析前,這里先對(duì) buildAspectJAdvisors 方法的執(zhí)行流程做個(gè)總結(jié)。如下:
1.獲取容器中所有 bean 的名稱(chēng)(beanName)
遍歷上一步獲取到的 bean 名稱(chēng)數(shù)組,并獲取當(dāng)前 beanName 對(duì)應(yīng)的 bean 類(lèi)型(beanType)
根據(jù) beanType 判斷當(dāng)前 bean 是否是一個(gè)的 Aspect 注解類(lèi),若不是則不做任何處理
調(diào)用 advisorFactory.getAdvisors 獲取通知器
public List<Advisor> getAdvisors(MetadataAwareAspectInstanceFactory aspectInstanceFactory) {
// 獲取 aspectClass 和 aspectName
Class<?> aspectClass = aspectInstanceFactory.getAspectMetadata().getAspectClass();
String aspectName = aspectInstanceFactory.getAspectMetadata().getAspectName();
validate(aspectClass);
MetadataAwareAspectInstanceFactory lazySingletonAspectInstanceFactory =
new LazySingletonAspectInstanceFactoryDecorator(aspectInstanceFactory);
List<Advisor> advisors = new LinkedList<Advisor>();
// getAdvisorMethods 用于返回不包含 @Pointcut 注解的方法
for (Method method : getAdvisorMethods(aspectClass)) {
// 為每個(gè)方法分別調(diào)用 getAdvisor 方法
Advisor advisor = getAdvisor(method, lazySingletonAspectInstanceFactory, advisors.size(), aspectName);
if (advisor != null) {
advisors.add(advisor);
}
}
// If it's a per target aspect, emit the dummy instantiating aspect.
if (!advisors.isEmpty() && lazySingletonAspectInstanceFactory.getAspectMetadata().isLazilyInstantiated()) {
Advisor instantiationAdvisor = new SyntheticInstantiationAdvisor(lazySingletonAspectInstanceFactory);
advisors.add(0, instantiationAdvisor);
}
// Find introduction fields.
for (Field field : aspectClass.getDeclaredFields()) {
Advisor advisor = getDeclareParentsAdvisor(field);
if (advisor != null) {
advisors.add(advisor);
}
}
return advisors;
}
public Advisor getAdvisor(Method candidateAdviceMethod, MetadataAwareAspectInstanceFactory aspectInstanceFactory,
int declarationOrderInAspect, String aspectName) {
validate(aspectInstanceFactory.getAspectMetadata().getAspectClass());
// 獲取切點(diǎn)實(shí)現(xiàn)類(lèi)
AspectJExpressionPointcut expressionPointcut = getPointcut(
candidateAdviceMethod, aspectInstanceFactory.getAspectMetadata().getAspectClass());
if (expressionPointcut == null) {
return null;
}
// 創(chuàng)建 Advisor 實(shí)現(xiàn)類(lèi)
return new InstantiationModelAwarePointcutAdvisorImpl(expressionPointcut, candidateAdviceMethod,
this, aspectInstanceFactory, declarationOrderInAspect, aspectName);
}
如上,getAdvisor 方法包含兩個(gè)主要步驟,一個(gè)是獲取 AspectJ 表達(dá)式切點(diǎn),另一個(gè)是創(chuàng)建 Advisor 實(shí)現(xiàn)類(lèi)。在第二個(gè)步驟中,包含一個(gè)隱藏步驟 – 創(chuàng)建 Advice。下面我將按順序依次分析這兩個(gè)步驟,先看獲取 AspectJ 表達(dá)式切點(diǎn)的過(guò)程,如下:
private AspectJExpressionPointcut getPointcut(Method candidateAdviceMethod, Class<?> candidateAspectClass) {
// 獲取方法上的 AspectJ 相關(guān)注解,包括 @Before,@After 等
AspectJAnnotation<?> aspectJAnnotation =
AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(candidateAdviceMethod);
if (aspectJAnnotation == null) {
return null;
}
// 創(chuàng)建一個(gè) AspectJExpressionPointcut 對(duì)象
AspectJExpressionPointcut ajexp =
new AspectJExpressionPointcut(candidateAspectClass, new String[0], new Class<?>[0]);
// 設(shè)置切點(diǎn)表達(dá)式
ajexp.setExpression(aspectJAnnotation.getPointcutExpression());
ajexp.setBeanFactory(this.beanFactory);
return ajexp;
}
protected static AspectJAnnotation<?> findAspectJAnnotationOnMethod(Method method) {
// classesToLookFor 中的元素是大家熟悉的
Class<?>[] classesToLookFor = new Class<?>[] {
Before.class, Around.class, After.class, AfterReturning.class, AfterThrowing.class, Pointcut.class};
for (Class<?> c : classesToLookFor) {
// 查找注解
AspectJAnnotation<?> foundAnnotation = findAnnotation(method, (Class<Annotation>) c);
if (foundAnnotation != null) {
return foundAnnotation;
}
}
return null;
}
獲取切點(diǎn)的過(guò)程并不復(fù)雜,不過(guò)需要注意的是,目前獲取到的切點(diǎn)可能還只是個(gè)半成品,需要再次處理一下才行。比如下面的代碼:
@Aspect
public class AnnotationAopCode {
@Pointcut("execution(* xyz.coolblog.aop.*.world*(..))")
public void pointcut() {}
@Before("pointcut()")
public void before() {
System.out.println("AnnotationAopCode`s before");
}
}
@Before 注解中的表達(dá)式是pointcut(),也就是說(shuō) ajexp 設(shè)置的表達(dá)式只是一個(gè)中間值,不是最終值,即execution(* xyz.coolblog.aop..world(..))。所以后續(xù)還需要將 ajexp 中的表達(dá)式進(jìn)行轉(zhuǎn)換,關(guān)于這個(gè)轉(zhuǎn)換的過(guò)程,我就不說(shuō)了。有點(diǎn)復(fù)雜,我暫時(shí)沒(méi)怎么看懂。
說(shuō)完切點(diǎn)的獲取過(guò)程,下面再來(lái)看看 Advisor 實(shí)現(xiàn)類(lèi)的創(chuàng)建過(guò)程。如下:
public InstantiationModelAwarePointcutAdvisorImpl(AspectJExpressionPointcut declaredPointcut,
Method aspectJAdviceMethod, AspectJAdvisorFactory aspectJAdvisorFactory,
MetadataAwareAspectInstanceFactory aspectInstanceFactory, int declarationOrder, String aspectName) {
this.declaredPointcut = declaredPointcut;
this.declaringClass = aspectJAdviceMethod.getDeclaringClass();
this.methodName = aspectJAdviceMethod.getName();
this.parameterTypes = aspectJAdviceMethod.getParameterTypes();
this.aspectJAdviceMethod = aspectJAdviceMethod;
this.aspectJAdvisorFactory = aspectJAdvisorFactory;
this.aspectInstanceFactory = aspectInstanceFactory;
this.declarationOrder = declarationOrder;
this.aspectName = aspectName;
if (aspectInstanceFactory.getAspectMetadata().isLazilyInstantiated()) {
Pointcut preInstantiationPointcut = Pointcuts.union(
aspectInstanceFactory.getAspectMetadata().getPerClausePointcut(), this.declaredPointcut);
this.pointcut = new PerTargetInstantiationModelPointcut(
this.declaredPointcut, preInstantiationPointcut, aspectInstanceFactory);
this.lazy = true;
}
else {
this.pointcut = this.declaredPointcut;
this.lazy = false;
// 按照注解解析 Advice
this.instantiatedAdvice = instantiateAdvice(this.declaredPointcut);
}
}
上面是 InstantiationModelAwarePointcutAdvisorImpl 的構(gòu)造方法,不過(guò)我們無(wú)需太關(guān)心這個(gè)方法中的一些初始化邏輯。我們把目光移到構(gòu)造方法的最后一行代碼中,即 instantiateAdvice(this.declaredPointcut),這個(gè)方法用于創(chuàng)建通知 Advice。在上一篇文章中我已經(jīng)說(shuō)過(guò),通知器 Advisor 是通知 Advice 的持有者,所以在 Advisor 實(shí)現(xiàn)類(lèi)的構(gòu)造方法中創(chuàng)建通知也是合適的。那下面我們就來(lái)看看構(gòu)建通知的過(guò)程是怎樣的,如下:
private Advice instantiateAdvice(AspectJExpressionPointcut pcut) {
return this.aspectJAdvisorFactory.getAdvice(this.aspectJAdviceMethod, pcut,
this.aspectInstanceFactory, this.declarationOrder, this.aspectName);
}
public Advice getAdvice(Method candidateAdviceMethod, AspectJExpressionPointcut expressionPointcut,
MetadataAwareAspectInstanceFactory aspectInstanceFactory, int declarationOrder, String aspectName) {
Class<?> candidateAspectClass = aspectInstanceFactory.getAspectMetadata().getAspectClass();
validate(candidateAspectClass);
// 獲取 Advice 注解
AspectJAnnotation<?> aspectJAnnotation =
AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(candidateAdviceMethod);
if (aspectJAnnotation == null) {
return null;
}
if (!isAspect(candidateAspectClass)) {
throw new AopConfigException("Advice must be declared inside an aspect type: " +
"Offending method '" + candidateAdviceMethod + "' in class [" +
candidateAspectClass.getName() + "]");
}
if (logger.isDebugEnabled()) {
logger.debug("Found AspectJ method: " + candidateAdviceMethod);
}
AbstractAspectJAdvice springAdvice;
// 按照注解類(lèi)型生成相應(yīng)的 Advice 實(shí)現(xiàn)類(lèi)
switch (aspectJAnnotation.getAnnotationType()) {
case AtBefore: // @Before -> AspectJMethodBeforeAdvice
springAdvice = new AspectJMethodBeforeAdvice(
candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
break;
case AtAfter: // @After -> AspectJAfterAdvice
springAdvice = new AspectJAfterAdvice(
candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
break;
case AtAfterReturning: // @AfterReturning -> AspectJAfterAdvice
springAdvice = new AspectJAfterReturningAdvice(
candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
AfterReturning afterReturningAnnotation = (AfterReturning) aspectJAnnotation.getAnnotation();
if (StringUtils.hasText(afterReturningAnnotation.returning())) {
springAdvice.setReturningName(afterReturningAnnotation.returning());
}
break;
case AtAfterThrowing: // @AfterThrowing -> AspectJAfterThrowingAdvice
springAdvice = new AspectJAfterThrowingAdvice(
candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
AfterThrowing afterThrowingAnnotation = (AfterThrowing) aspectJAnnotation.getAnnotation();
if (StringUtils.hasText(afterThrowingAnnotation.throwing())) {
springAdvice.setThrowingName(afterThrowingAnnotation.throwing());
}
break;
case AtAround: // @Around -> AspectJAroundAdvice
springAdvice = new AspectJAroundAdvice(
candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
break;
/*
* 什么都不做,直接返回 null。從整個(gè)方法的調(diào)用棧來(lái)看,
* 并不會(huì)出現(xiàn)注解類(lèi)型為 AtPointcut 的情況
*/
case AtPointcut:
if (logger.isDebugEnabled()) {
logger.debug("Processing pointcut '" + candidateAdviceMethod.getName() + "'");
}
return null;
default:
throw new UnsupportedOperationException(
"Unsupported advice type on method: " + candidateAdviceMethod);
}
springAdvice.setAspectName(aspectName);
springAdvice.setDeclarationOrder(declarationOrder);
/*
* 獲取方法的參數(shù)列表名稱(chēng),比如方法 int sum(int numX, int numY),
* getParameterNames(sum) 得到 argNames = [numX, numY]
*/
String[] argNames = this.parameterNameDiscoverer.getParameterNames(candidateAdviceMethod);
if (argNames != null) {
// 設(shè)置參數(shù)名
springAdvice.setArgumentNamesFromStringArray(argNames);
}
springAdvice.calculateArgumentBindings();
return springAdvice;
}
上面的代碼邏輯不是很復(fù)雜,主要的邏輯就是根據(jù)注解類(lèi)型生成與之對(duì)應(yīng)的通知對(duì)象。下面來(lái)總結(jié)一下獲取通知器(getAdvisors)整個(gè)過(guò)程的邏輯,如下:
1.從目標(biāo) bean 中獲取不包含 Pointcut 注解的方法列表
2.遍歷上一步獲取的方法列表,并調(diào)用 getAdvisor 獲取當(dāng)前方法對(duì)應(yīng)的 Advisor
3.創(chuàng)建 AspectJExpressionPointcut 對(duì)象,并從方法中的注解中獲取表達(dá)式,最后設(shè)置到切點(diǎn)對(duì)象中
4.創(chuàng)建 Advisor 實(shí)現(xiàn)類(lèi)對(duì)象 InstantiationModelAwarePointcutAdvisorImpl
5.調(diào)用 instantiateAdvice 方法構(gòu)建通知
6.調(diào)用 getAdvice 方法,并根據(jù)注解類(lèi)型創(chuàng)建相應(yīng)的通知
如上所示,上面的步驟做了一定的簡(jiǎn)化??偟膩?lái)說(shuō),獲取通知器的過(guò)程還是比較復(fù)雜的,并不是很容易看懂。大家在閱讀的過(guò)程中,還要寫(xiě)一些測(cè)試代碼進(jìn)行調(diào)試才行。調(diào)試的過(guò)程中,一些不關(guān)心的調(diào)用就別跟進(jìn)去了,不然會(huì)陷入很深的調(diào)用棧中,影響對(duì)源碼主流程的理解。
現(xiàn)在,大家知道了通知是怎么創(chuàng)建的。那我們難道不要去看看這些通知的實(shí)現(xiàn)源碼嗎?顯然,我們應(yīng)該看一下。那接下里,我們一起來(lái)分析一下 AspectJMethodBeforeAdvice,也就是 @Before 注解對(duì)應(yīng)的通知實(shí)現(xiàn)類(lèi)。看看它的邏輯是什么樣的。
2.3 AspectJMethodBeforeAdvice 分析
public class AspectJMethodBeforeAdvice extends AbstractAspectJAdvice implements MethodBeforeAdvice {
public AspectJMethodBeforeAdvice(
Method aspectJBeforeAdviceMethod, AspectJExpressionPointcut pointcut, AspectInstanceFactory aif) {
super(aspectJBeforeAdviceMethod, pointcut, aif);
}
@Override
public void before(Method method, Object[] args, Object target) throws Throwable {
// 調(diào)用通知方法
invokeAdviceMethod(getJoinPointMatch(), null, null);
}
@Override
public boolean isBeforeAdvice() {
return true;
}
@Override
public boolean isAfterAdvice() {
return false;
}
}
protected Object invokeAdviceMethod(JoinPointMatch jpMatch, Object returnValue, Throwable ex) throws Throwable {
// 調(diào)用通知方法,并向其傳遞參數(shù)
return invokeAdviceMethodWithGivenArgs(argBinding(getJoinPoint(), jpMatch, returnValue, ex));
}
protected Object invokeAdviceMethodWithGivenArgs(Object[] args) throws Throwable {
Object[] actualArgs = args;
if (this.aspectJAdviceMethod.getParameterTypes().length == 0) {
actualArgs = null;
}
try {
ReflectionUtils.makeAccessible(this.aspectJAdviceMethod);
// 通過(guò)反射調(diào)用通知方法
return this.aspectJAdviceMethod.invoke(this.aspectInstanceFactory.getAspectInstance(), actualArgs);
}
catch (IllegalArgumentException ex) {
throw new AopInvocationException("Mismatch on arguments to advice method [" +
this.aspectJAdviceMethod + "]; pointcut expression [" +
this.pointcut.getPointcutExpression() + "]", ex);
}
catch (InvocationTargetException ex) {
throw ex.getTargetException();
}
}
如上,AspectJMethodBeforeAdvice 的源碼比較簡(jiǎn)單,這里我們僅關(guān)注 before 方法。這個(gè)方法調(diào)用了父類(lèi)中的 invokeAdviceMethod,然后 invokeAdviceMethod 在調(diào)用 invokeAdviceMethodWithGivenArgs,最后在 invokeAdviceMethodWithGivenArgs 通過(guò)反射執(zhí)行通知方法。
2.4 篩選通知器
查找出所有的通知器,整個(gè)流程還沒(méi)算完,接下來(lái)我們還要對(duì)這些通知器進(jìn)行篩選。適合應(yīng)用在當(dāng)前 bean 上的通知器留下,不適合的就讓它自生自滅吧。那下面我們來(lái)分析一下通知器篩選的過(guò)程,如下:
protected List<Advisor> findAdvisorsThatCanApply(
List<Advisor> candidateAdvisors, Class<?> beanClass, String beanName) {
ProxyCreationContext.setCurrentProxiedBeanName(beanName);
try {
// 調(diào)用重載方法
return AopUtils.findAdvisorsThatCanApply(candidateAdvisors, beanClass);
}
finally {
ProxyCreationContext.setCurrentProxiedBeanName(null);
}
}
public static List<Advisor> findAdvisorsThatCanApply(List<Advisor> candidateAdvisors, Class<?> clazz) {
if (candidateAdvisors.isEmpty()) {
return candidateAdvisors;
}
List<Advisor> eligibleAdvisors = new LinkedList<Advisor>();
for (Advisor candidate : candidateAdvisors) {
// 篩選 IntroductionAdvisor 類(lèi)型的通知器
if (candidate instanceof IntroductionAdvisor && canApply(candidate, clazz)) {
eligibleAdvisors.add(candidate);
}
}
boolean hasIntroductions = !eligibleAdvisors.isEmpty();
for (Advisor candidate : candidateAdvisors) {
if (candidate instanceof IntroductionAdvisor) {
continue;
}
// 篩選普通類(lèi)型的通知器
if (canApply(candidate, clazz, hasIntroductions)) {
eligibleAdvisors.add(candidate);
}
}
return eligibleAdvisors;
}
public static boolean canApply(Advisor advisor, Class<?> targetClass, boolean hasIntroductions) {
if (advisor instanceof IntroductionAdvisor) {
/*
* 從通知器中獲取類(lèi)型過(guò)濾器 ClassFilter,并調(diào)用 matchers 方法進(jìn)行匹配。
* ClassFilter 接口的實(shí)現(xiàn)類(lèi) AspectJExpressionPointcut 為例,該類(lèi)的
* 匹配工作由 AspectJ 表達(dá)式解析器負(fù)責(zé),具體匹配細(xì)節(jié)這個(gè)就沒(méi)法分析了,我
* AspectJ 表達(dá)式的工作流程不是很熟
*/
return ((IntroductionAdvisor) advisor).getClassFilter().matches(targetClass);
}
else if (advisor instanceof PointcutAdvisor) {
PointcutAdvisor pca = (PointcutAdvisor) advisor;
// 對(duì)于普通類(lèi)型的通知器,這里繼續(xù)調(diào)用重載方法進(jìn)行篩選
return canApply(pca.getPointcut(), targetClass, hasIntroductions);
}
else {
return true;
}
以上是通知器篩選的過(guò)程,篩選的工作主要由 ClassFilter 和 MethodMatcher 完成。在 AOP 中,切點(diǎn) Pointcut 是用來(lái)匹配連接點(diǎn)的,以 AspectJExpressionPointcut 類(lèi)型的切點(diǎn)為例。該類(lèi)型切點(diǎn)實(shí)現(xiàn)了ClassFilter 和 MethodMatcher 接口,匹配的工作則是由 AspectJ 表達(dá)式解析器復(fù)雜。除了使用 AspectJ 表達(dá)式進(jìn)行匹配,Spring 還提供了基于正則表達(dá)式的切點(diǎn)類(lèi),以及更簡(jiǎn)單的根據(jù)方法名進(jìn)行匹配的切點(diǎn)類(lèi)。大家有興趣的話(huà),可以自己去了解一下,這里就不多說(shuō)了。
在完成通知器的查找和篩選過(guò)程后,還需要進(jìn)行最后一步處理 – 對(duì)通知器列表進(jìn)行拓展。怎么拓展呢?我們一起到下一節(jié)中一探究竟吧。
2.5 拓展篩選出通知器列表
拓展方法 extendAdvisors 做的事情并不多,邏輯也比較簡(jiǎn)單。我們一起來(lái)看一下,如下:
protected void extendAdvisors(List<Advisor> candidateAdvisors) {
AspectJProxyUtils.makeAdvisorChainAspectJCapableIfNecessary(candidateAdvisors);
}
public static boolean makeAdvisorChainAspectJCapableIfNecessary(List<Advisor> advisors) {
// 如果通知器列表是一個(gè)空列表,則啥都不做
if (!advisors.isEmpty()) {
boolean foundAspectJAdvice = false;
/*
* 下面的 for 循環(huán)用于檢測(cè) advisors 列表中是否存在
* AspectJ 類(lèi)型的 Advisor 或 Advice
*/
for (Advisor advisor : advisors) {
if (isAspectJAdvice(advisor)) {
foundAspectJAdvice = true;
}
}
/*
* 向 advisors 列表的首部添加 DefaultPointcutAdvisor,
* 至于為什么這樣做,我會(huì)在后續(xù)的文章中進(jìn)行說(shuō)明
*/
if (foundAspectJAdvice && !advisors.contains(ExposeInvocationInterceptor.ADVISOR)) {
advisors.add(0, ExposeInvocationInterceptor.ADVISOR);
return true;
}
}
return false;
}
private static boolean isAspectJAdvice(Advisor advisor) {
return (advisor instanceof InstantiationModelAwarePointcutAdvisor ||
advisor.getAdvice() instanceof AbstractAspectJAdvice ||
(advisor instanceof PointcutAdvisor &&
((PointcutAdvisor) advisor).getPointcut() instanceof AspectJExpressionPointcut));
}
如上,上面的代碼比較少,也不復(fù)雜。由源碼可以看出 extendAdvisors 是一個(gè)空殼方法,除了調(diào)用makeAdvisorChainAspectJCapableIfNecessary,該方法沒(méi)有其他更多的邏輯了。至于 makeAdvisorChainAspectJCapableIfNecessary 這個(gè)方法,該方法主要的目的是向通知器列表首部添加 DefaultPointcutAdvisor 類(lèi)型的通知器,也就是 ExposeInvocationInterceptor.ADVISOR。至于添加此種類(lèi)型通知器的意圖,我會(huì)在后面文章里說(shuō)明,這里不便展開(kāi)。關(guān)于 extendAdvisors 這個(gè)方法,這里就先說(shuō)到這了。
3.總結(jié)
到這里,本篇文章就接近尾聲了。這篇文章有點(diǎn)長(zhǎng),大家看下來(lái)應(yīng)該蠻累的吧。由于個(gè)人能力問(wèn)題,暫時(shí)未能做到對(duì)本篇文章中所貼的源碼進(jìn)行更為細(xì)致的分析,有點(diǎn)遺憾。不過(guò)好在目前把主邏輯分析弄清楚了,總的來(lái)說(shuō)還算合格吧,給個(gè)及格分。大家在閱讀的過(guò)程中,如果發(fā)現(xiàn)文章中出現(xiàn)錯(cuò)誤或不妥之處,這里還請(qǐng)指明,也請(qǐng)多多指教。大家共同學(xué)習(xí),一起進(jìn)步。
好了,本篇文章就到這里了。謝謝大家的閱讀。