[Spring]AnnotationAwareAspectJAutoProxyCreator-@AspectJ的解析器

AnnotationAwareAspectJAutoProxyCreator職能

AnnotationAwareAspectJAutoProxyCreator是用來處理被@AspectJ注解標(biāo)注的切面類和Spring Advisors的.
其中,Spring Advisors的處理規(guī)則遵循AbstractAdvisorAutoProxyCreator中建立的規(guī)則.

UML

UML

我們從類圖可以看到,AnnotationAwareAspectJAutoProxyCreator的組成結(jié)構(gòu)還是稍微復(fù)雜的。下面我們來過一下其中比較重要的接口.

  • AopInfrastructureBean: 實現(xiàn)該接口的類會被標(biāo)記為Spring內(nèi)部的基礎(chǔ)類,Spring AOP并不會對這類型的Bean進(jìn)行代理.
  • 與Aware相關(guān)的接口: 通過此類接口獲取容器的BeanFactory和ClassLoader.
  • ProxyConfig: 用于創(chuàng)建代理的配置類,以確保所有代理創(chuàng)建者都具有一致的屬性.內(nèi)部可配置proxyTargetClassexposeProxy、optimize等屬性
  • ProxyProcessorSupport: 具有代理處理器通用功能的基類,此外,還特地提供了ClassLoader的管理和evaluateProxyInterfaces方法,ProxyFactory可以通過evaluateProxyInterfaces方法獲取給定bean類上的接口.
  • InstantiationAwareBeanPostProcessor: Spring AOP中會在實例化前判斷是否需要創(chuàng)建用戶自定義的代理類,進(jìn)而影響Spring Bean的聲明周期.
  • SmartInstantiationAwareBeanPostProcessor: 重量級方法->getEarlyBeanReference,當(dāng)Spring Bean發(fā)生循環(huán)依賴的時候,決定是否要將創(chuàng)建代理的時機(jī)提前.
  • BeanPostProcessor: AbstractAutoProxyCreator會在postProcessAfterInitialization中來解析當(dāng)前Bean是否需要代理,正常的Bean是在此處進(jìn)行代理的,當(dāng)執(zhí)行到這步的時候,通常Spring Bean已經(jīng)完成實例化、初始化了。
  • AbstractAutoProxyCreator: 繼承了ProxyProcessorSupportSmartInstantiationAwareBeanPostProcessor,是Spring AOP的代理創(chuàng)建器,將匹配代理的地方交由子類去實現(xiàn).同時,它還是getEarlyBeanReference方法的實現(xiàn)者.
  • AbstractAdvisorAutoProxyCreator: 提供為每個Bean選擇特定的advisor進(jìn)行代理的功能,提供findCandidateAdvisorsgetAdvicesAndAdvisorsForBean方法用于尋找候選的advisors和為bean匹配advisors.
  • AspectJAwareAdvisorAutoProxyCreator: 提供了對advisors進(jìn)行排序的功能,同時為了兼容XML的切面配置解析,也保留了shouldSkip
  • AnnotationAwareAspectJAutoProxyCreator: Spring用于解析切面類,將需要執(zhí)行的通知方法轉(zhuǎn)化成Spring Advisor.

Spring Advisor

Spring中的Advisor接口是Spring AOP的基礎(chǔ)接口,一個Advisor可以持有一個pointcut和一個AOP advice.Spring AOP正是通過將被AspectJ標(biāo)注的類中的不同Advice解析成Advisor調(diào)用鏈來執(zhí)行切面邏輯的。

Advised-操作Advisor

public interface Advised extends TargetClassAware {

    // 返回當(dāng)前的advised配置是否被凍結(jié)
    boolean isFrozen();

    // 代理完整的目標(biāo)類而不是指定的接口
    boolean isProxyTargetClass();

    // 返回由AOP代理代理的接口。
    // 將不包括目標(biāo)類別,也可以將其作為代理。
    Class<?>[] getProxiedInterfaces();

    // 確定是否代理給定的接口
    boolean isInterfaceProxied(Class<?> intf);

    // 更改此建議對象使用的TargetSource。
    // 僅在未凍結(jié)配置的情況下有效。
    void setTargetSource(TargetSource targetSource);

    // 返回此Advised對象使用的TargetSource。
    TargetSource getTargetSource();

    // 設(shè)置代理是否應(yīng)由AOP框架公開為ThreadLocal以便通過AopContext類進(jìn)行檢索。
    // 默認(rèn)值為false,以實現(xiàn)最佳性能。
    void setExposeProxy(boolean exposeProxy);

    // 當(dāng)前代理工廠是是否將代理類引用通過ThrealLocal管理起來.
    boolean isExposeProxy();

    // 獲取當(dāng)前代理的所有advisors
    Advisor[] getAdvisors();

    // 向當(dāng)前proxy的advisor調(diào)用鏈追加一個advisor
    void addAdvisor(Advisor advisor) throws AopConfigException;

    // 向當(dāng)前proxy的advisor調(diào)用鏈中的某個位置插入一個advisor
    void addAdvisor(int pos, Advisor advisor) throws AopConfigException;

    // 移除給定的advisor
    boolean removeAdvisor(Advisor advisor);

    // 移除某個位置中的advisor
    void removeAdvisor(int index) throws AopConfigException;

    // 獲取當(dāng)前advisor在執(zhí)行鏈中的位置. -1代表沒有任何的advisor
    int indexOf(Advisor advisor);

    // 替代某個advisor
    boolean replaceAdvisor(Advisor a, Advisor b) throws AopConfigException;

    // 向advice的攔截鏈中添加給定的AOP Alliance advice
    void addAdvice(Advice advice) throws AopConfigException;

    void addAdvice(int pos, Advice advice) throws AopConfigException;

    boolean removeAdvice(Advice advice);

    int indexOf(Advice advice);

    // 返回AOP代理的配置項。
    String toProxyConfigString();

}

Spring 官網(wǎng)對advised接口的描述

TargetSource

Spring AOP并不是直接代理目標(biāo)類,而是通過代理TargetSource接口進(jìn)而實現(xiàn)動態(tài)代理.
簡單來說即: Spring AOP->TargetSource->targetObject

  • UML
targetSource

Spring官網(wǎng)對TargerSource的介紹

加載切面類并解析advisor

  • AbstractAutoProxyCreator#postProcessBeforeInstantiation
public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) {
        // 從緩存中獲取當(dāng)前BeanClass的Class對象,在advisedBeans這個Map中,以class為key
        // 同時,該class還充當(dāng)proxyTypes這個Map中的key
        Object cacheKey = getCacheKey(beanClass, beanName);

        if (!StringUtils.hasLength(beanName) || !this.targetSourcedBeans.contains(beanName)) {
            // 如果當(dāng)前類已經(jīng)被動態(tài)代理了,不進(jìn)行任何操作
            if (this.advisedBeans.containsKey(cacheKey)) {
                return null;
            }
            // 當(dāng)前beanClass是否實現(xiàn)Advice、Pointcut、Advisor、AopInfrastructureBean
            // 是否需要跳過解析
            if (isInfrastructureClass(beanClass) || shouldSkip(beanClass, beanName)) {
                this.advisedBeans.put(cacheKey, Boolean.FALSE);
                return null;
            }
        }

        // 如果當(dāng)前beanClass存在用戶自定義的TargetSource,則進(jìn)行代理
        // 在Spring AOP中,動態(tài)代理并不是直接代理target對象的,而是通過代理TargetSource來間接代理target對象
        TargetSource targetSource = getCustomTargetSource(beanClass, beanName);
        if (targetSource != null) {
            if (StringUtils.hasLength(beanName)) {
                this.targetSourcedBeans.add(beanName);
            }
            // 獲取當(dāng)前bean的advisors
            Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(beanClass, beanName, targetSource);
            // 創(chuàng)建代理類
            Object proxy = createProxy(beanClass, beanName, specificInterceptors, targetSource);
            this.proxyTypes.put(cacheKey, proxy.getClass());
            return proxy;
        }

        return null;
    }
  1. 需要過濾已經(jīng)創(chuàng)建過動態(tài)代理的類,advisedBeans這個Map便是緩存已經(jīng)被Spring AOP處理過的BeanClass.
  2. 其中isInfrastructureClass會過濾掉Spring AOP框架內(nèi)部的基類,同時會識別當(dāng)前是否標(biāo)注了@AspectJ與被ajc編譯器所編譯.
  3. 如果當(dāng)前用戶自定義實現(xiàn)了TargetSource接口,那么AbstractAutoProxyCreator會為用戶自定義的TargetSource創(chuàng)建代理.

我們深入isInfrastructureClass這個方法看看,step into!

isInfrastructureClass-忽略Spring AOP的基礎(chǔ)服務(wù)類

  • org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator#isInfrastructureClass
@Override
    protected boolean isInfrastructureClass(Class<?> beanClass) {
        
        return (super.isInfrastructureClass(beanClass) ||
                (this.aspectJAdvisorFactory != null && this.aspectJAdvisorFactory.isAspect(beanClass)));
    }

父類中的AbstractAutoProxyCreator調(diào)用了AnnotationAwareAspectJAutoProxyCreator中的isInfrastructureClass,這里有2個判斷:

  1. 調(diào)用父類的isInfrastructureClass,返回true則直接中斷.
    父類執(zhí)行isInfrastructureClass的邏輯為:當(dāng)前beanClass是否實現(xiàn)Advice、PointcutAdvisor、AopInfrastructureBean.
  2. 判斷當(dāng)前beanClass是否為切面類.isApsect的邏輯比較簡單:beanClass上是否標(biāo)注了@Aspect注解并且沒有被ajc編譯器編譯過.
  • org.springframework.aop.aspectj.annotation.AbstractAspectJAdvisorFactory#isAspect
    public boolean isAspect(Class<?> clazz) {
        // 類上是否標(biāo)注@Aspect并且沒有被ajc編譯器編譯過
        return (hasAspectAnnotation(clazz) && !compiledByAjc(clazz));
    }

shouldSkip-將切面類解析成advisor

  • org.springframework.aop.aspectj.autoproxy.AspectJAwareAdvisorAutoProxyCreator#shouldSkip
@Override
protected boolean shouldSkip(Class<?> beanClass, String beanName) {
    // TODO: Consider optimization by caching the list of the aspect names
    // 查找候選的advisors
    List<Advisor> candidateAdvisors = findCandidateAdvisors();
    for (Advisor advisor : candidateAdvisors) {
        if (advisor instanceof AspectJPointcutAdvisor &&
                ((AspectJPointcutAdvisor) advisor).getAspectName().equals(beanName)) {
            return true;
        }
    }
    return super.shouldSkip(beanClass, beanName);
}

shouldSkip是Spring AOP構(gòu)建advisor的入口,spring會在每次執(zhí)行postProcessBeforeInstantiation的時候,解析每個advisor,解析完成后將advisors進(jìn)行緩存,進(jìn)而判斷當(dāng)前的beanClass和beanName是否已經(jīng)解析完畢. 下面,我們來看看findCandidateAdvisors這個方法做了什么,step into.

  • org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator#findCandidateAdvisors
@Override
protected List<Advisor> findCandidateAdvisors() {
    // Add all the Spring advisors found according to superclass rules.
    // 添加根據(jù)超類規(guī)則找到的所有Spring advisors.從層級關(guān)系我們可以知道,
    // AspectJAwareAdvisorAutoProxyCreator提供對XML或者實現(xiàn)接口的AOP配置解析
    List<Advisor> advisors = super.findCandidateAdvisors();
    // Build Advisors for all AspectJ aspects in the bean factory.
    if (this.aspectJAdvisorsBuilder != null) {
        // 注解驅(qū)動的AOP切面解析類解析
        advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors());
    }
    return advisors;
}

這里面findCandidateAdvisors分成了兩條線路:

  1. 調(diào)用父類AspectJAwareAdvisorAutoProxyCreator#finCandidateAdvisors提供對XML或者實現(xiàn)接口的AOP配置解析成advisor列表.
  2. 解析注解形式的Aspect成advisor列表.

最后,都添加進(jìn)advisor列表中.

解析advisor類型的bean.
  • org.springframework.aop.framework.autoproxy.AbstractAdvisorAutoProxyCreator#findCandidateAdvisors
protected List<Advisor> findCandidateAdvisors() {
Assert.state(this.advisorRetrievalHelper != null, "No BeanFactoryAdvisorRetrievalHelper available");
// BeanFactoryAdvisorRetrievalHelperAdapter#findAdvisorBeans
return this.advisorRetrievalHelper.findAdvisorBeans();
}

這里進(jìn)行了一個helper的委托,真正執(zhí)行者為BeanFactoryAdvisorRetrievalHelperAdapter#findAdvisorBeans.

  • org.springframework.aop.framework.autoproxy.BeanFactoryAdvisorRetrievalHelper#findAdvisorBeans
/**
 * <p>Find all eligible Advisor beans in the current bean factory,
 * ignoring FactoryBeans and excluding beans that are currently in creation.</p>
 * 在當(dāng)前beanFactory中查找所有有資格的advisor.<br>
 * 對FactoryBean和正在創(chuàng)建中的bean不生效 <br>
 * @return the list of {@link org.springframework.aop.Advisor} beans
 * @see #isEligibleBean
 */
public List<Advisor> findAdvisorBeans() {
    // Determine list of advisor bean names, if not cached already.
    // 從緩存中獲取容器中所有的advisor bean的名字?jǐn)?shù)組
    String[] advisorNames = this.cachedAdvisorBeanNames;
    if (advisorNames == null) {
        // Do not initialize FactoryBeans here: We need to leave all regular beans
        // uninitialized to let the auto-proxy creator apply to them!
        // 如果緩存中沒有,那么從容器中以及其父容器中分析得到所有的advisor bean的名稱
        // BeanFactoryUtils.beanNamesForTypeIncludingAncestors此處是找到類型為advisor的bean
        // 注意,spring不推薦在此處實例化factoryBeans,因為spring需要保留所有未初始化的常規(guī)類
        // 以使自動代理創(chuàng)建者對其應(yīng)用!
        advisorNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
                this.beanFactory, Advisor.class, true, false);
        // 回種緩存
        this.cachedAdvisorBeanNames = advisorNames;
    }
    if (advisorNames.length == 0) {
        return new ArrayList<>();
    }

    List<Advisor> advisors = new ArrayList<>();
    for (String name : advisorNames) {
        // 是否為合適的bean,提供給用戶自定義實現(xiàn),默認(rèn)返回true
        if (isEligibleBean(name)) {
            // 創(chuàng)建中的bean會被忽略,beanPostProcessor是每次加載bean都會觸發(fā)的鉤子
            // 所以在下次進(jìn)來時,可能當(dāng)前正在創(chuàng)建的bean已經(jīng)被創(chuàng)建好了
            if (this.beanFactory.isCurrentlyInCreation(name)) {
                if (logger.isTraceEnabled()) {
                    logger.trace("Skipping currently created advisor '" + name + "'");
                }
            }
            else {
                try {
                    // 根據(jù)advisorName獲取advisor實例
                    advisors.add(this.beanFactory.getBean(name, Advisor.class));
                }
                catch (BeanCreationException ex) {
                    // 省略處理異常細(xì)節(jié)
                }
            }
        }
    }
    return advisors;
}

首先,會嘗試從緩存中獲取advisorNames數(shù)組,里面存儲了容器中所有的advisor bean的名字.如果無法從緩存中獲取,那么重新加載符合條件的advisorNames數(shù)組,回種緩存.這里要注意: BeanFactoryUtils.beanNamesForTypeIncludingAncestors( this.beanFactory, Advisor.class, true, false);中,傳入的是Advisor類型.,也就是尋找類型為Advisor的beanName,并非所有beanName.

遍歷advisorNames數(shù)組,對符合條件的advisor進(jìn)行getBean操作,然后添加進(jìn)advisors集合返回.

buildAspectJAdvisors-解析被@Aspect注解標(biāo)記的類

/**
 * Look for AspectJ-annotated aspect beans in the current bean factory,
 * and return to a list of Spring AOP Advisors representing them.
 * <p>Creates a Spring Advisor for each AspectJ advice method.<br>
 * 1. 從容器獲取所有的beanName集合 <br>
 * 2. 找到其中被@AspectJ標(biāo)注的類 <br>
 * 3. 解析Aspect類,將其轉(zhuǎn)化成advisors <br>
 * 4. 將result加入cache中 <br>
 * @return the list of {@link org.springframework.aop.Advisor} beans
 * @see #isEligibleBean
 */
public List<Advisor> buildAspectJAdvisors() {
    // 獲取所有aspect類的beanName
    List<String> aspectNames = this.aspectBeanNames;
    // 如果aspectNames為空,那么進(jìn)行加載
    if (aspectNames == null) {
        // 雙重檢查鎖,防止多線程之間產(chǎn)生并發(fā)訪問
        synchronized (this) {
            aspectNames = this.aspectBeanNames;
            if (aspectNames == null) {
                List<Advisor> advisors = new ArrayList<>();
                // 保存切面名稱的集合
                aspectNames = new ArrayList<>();
                // 獲取所有的beanName
                // BeanFactoryUtils.beanNamesForTypeIncludingAncestors傳入的type為Object
                // 也就說查找所有的bean,spring在這里使用了緩存,避免每次加載消耗性能
                String[] beanNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
                        this.beanFactory, Object.class, true, false);
                // 遍歷所有的beanName
                for (String beanName : beanNames) {
                    if (!isEligibleBean(beanName)) {
                        continue;
                    }
                    // We must be careful not to instantiate beans eagerly as in this case they
                    // would be cached by the Spring container but would not have been weaved.
                    // 必須小心,不要急于實例化bean,因為在這種情況下,它們將由Spring容器緩存,但不會被編織。
                    // 獲取bean的類型
                    Class<?> beanType = this.beanFactory.getType(beanName);
                    if (beanType == null) {
                        continue;
                    }
                    // org.springframework.aop.aspectj.annotation.AbstractAspectJAdvisorFactory.isAspect
                    // 篩選出當(dāng)前class是否標(biāo)記了@Apsect注解
                    if (this.advisorFactory.isAspect(beanType)) {
                        // 將當(dāng)前的beanName加入到aspectNames這個緩存中
                        aspectNames.add(beanName);
                        // 獲取當(dāng)前beanClass的aspect元數(shù)據(jù)
                        // AjType中包含了切面的詳細(xì)數(shù)據(jù)
                        AspectMetadata amd = new AspectMetadata(beanType, beanName);
                        // 獲取切面的種類,通常為singleton
                        if (amd.getAjType().getPerClause().getKind() == PerClauseKind.SINGLETON) {
                            MetadataAwareAspectInstanceFactory factory =
                                    new BeanFactoryAspectInstanceFactory(this.beanFactory, beanName);
                            // Aspect中的advice+pointcut可以組成一個個advisor
                            // 舉個例子,before、after、around每個都會搭配pointcut組成advisor
                            List<Advisor> classAdvisors = this.advisorFactory.getAdvisors(factory);
                            if (this.beanFactory.isSingleton(beanName)) {
                                // 如果bean是單例,存到單例緩存中
                                this.advisorsCache.put(beanName, classAdvisors);
                            }
                            else {
                                // 否則將工廠和beanName緩存
                                this.aspectFactoryCache.put(beanName, factory);
                            }
                            advisors.addAll(classAdvisors);
                        }
                        else {
                            // Per target or per this.
                            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 ArrayList<>();
    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;
}

方法比較長,但是總體的脈絡(luò)我們還是可以總結(jié)一下:

  1. 嘗試從緩存獲取所有的aspectNames集合.如果緩存找不到,重新加載.執(zhí)行的方法又是BeanFactoryUtils.beanNamesForTypeIncludingAncestors,只不過這次傳入的類型是Object.class,也就是說,獲取的是所有的beanNames.
  2. 遍歷beanNames數(shù)組,通過name獲取type,然后判斷當(dāng)前類是否為Aspect.也就是被@Aspect注解所標(biāo)記.
  3. 如果是Aspect,構(gòu)建AspectMetadata,AspectMetadata中保存了AjType,這是AspectJ框架的產(chǎn)物,通過它可以快速獲取當(dāng)前類的pointcutadvice等.Spring AOP正是借助AspectJ來獲取切面類的信息的.此外,AspectJ還提供了很多切面模型種類,通常,我們的切面類都是為singleton-單例.
  4. 調(diào)用ReflectiveAspectJAdvisorFactory#getAdvisors來解析Aspect類,進(jìn)而解析出List<Advisor>.
  • org.springframework.aop.aspectj.annotation.ReflectiveAspectJAdvisorFactory#getAdvisors
@Override
public List<Advisor> getAdvisors(MetadataAwareAspectInstanceFactory aspectInstanceFactory) {
    // 獲取Aspect類的class
    Class<?> aspectClass = aspectInstanceFactory.getAspectMetadata().getAspectClass();
    // 獲取Aspect的類名
    String aspectName = aspectInstanceFactory.getAspectMetadata().getAspectName();
    // 校驗切面類,不可以為抽象類,需標(biāo)記@Aspect
    // spring aop 不支持percflow、percflowbelow種類的aspect
    validate(aspectClass);

    // We need to wrap the MetadataAwareAspectInstanceFactory with a decorator
    // so that it will only instantiate once.
    // 使用裝飾器模式包裝MetadataAwareAspectInstanceFactory
    // 包裝器類重寫了getAspectInstance方法,并且保證當(dāng)前的factory在使用時才進(jìn)行加載(緩存)
    // 正如名字的意義一般 lazy singleton instance
    MetadataAwareAspectInstanceFactory lazySingletonAspectInstanceFactory =
            new LazySingletonAspectInstanceFactoryDecorator(aspectInstanceFactory);

    List<Advisor> advisors = new ArrayList<>();
    // 獲取aspect切面類中的所有方法,會過濾掉被@Pointcut標(biāo)記的方法
    // 獲取到的List<Method>按照Around, Before, After, AfterReturning, AfterThrowing的順序排序
    for (Method method : getAdvisorMethods(aspectClass)) {
        // 將方法解析成advisor
        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;
}

getAdvisors就是我們關(guān)注的注解切面類解析邏輯了:

  1. 首先從aspectInstanceFactory中獲取元數(shù)據(jù)進(jìn)而獲取切面類型和切面名稱,隨后對切面類進(jìn)行校驗-切面類不可以為抽象類,需標(biāo)記@Aspect,同時,spring aop 不支持percflow、percflowbelow種類的aspect.
  2. 使用裝飾器模式包裝MetadataAwareAspectInstanceFactory來懶加載切面類實例.
  3. 獲取當(dāng)前類中標(biāo)記@Pointcut注解外所有的Method集合,獲取到的List<Method>按照Around, Before, After, AfterReturning, AfterThrowing的順序排序.
  4. 遍歷每一個Method,將符合條件的方法解析成advisor實例.
  5. 檢查是否有屬于introduction的成員,如果有便進(jìn)行解析(@DeclareParents).
  6. 將解析完成的每一個advisor添加到返回的結(jié)果集中.
  • org.springframework.aop.aspectj.annotation.ReflectiveAspectJAdvisorFactory#getAdvisor
@Override
@Nullable
public Advisor getAdvisor(Method candidateAdviceMethod, MetadataAwareAspectInstanceFactory aspectInstanceFactory,
        int declarationOrderInAspect, String aspectName) {
    // 驗證aspectClass的合法性
    validate(aspectInstanceFactory.getAspectMetadata().getAspectClass());
    // 在切面的方法上構(gòu)建pointcut表達(dá)式
    AspectJExpressionPointcut expressionPointcut = getPointcut(
            candidateAdviceMethod, aspectInstanceFactory.getAspectMetadata().getAspectClass());
    if (expressionPointcut == null) {
        return null;
    }
    // 實例化切面中的advice對象
    return new InstantiationModelAwarePointcutAdvisorImpl(expressionPointcut, candidateAdviceMethod,
            this, aspectInstanceFactory, declarationOrderInAspect, aspectName);
}
  1. 校驗aspectClass的合法性,這個validate是復(fù)用的,跟上述的方法一致,邏輯就不重復(fù)講了.
  2. 根據(jù)當(dāng)前的adviceMethod與aspectClass構(gòu)建出AspectJExpressionPointcut實例.它是一個pointcut表達(dá)式的實例.里面對AspectJ框架的表達(dá)式原語進(jìn)行了部分的支持(11種).
  3. 通過getPointcut()獲取到切點(diǎn)表達(dá)式之后,接下來就可以實例化adivce然后構(gòu)建出advisor了,因為一個advisor = pointcut+advice.我們接著看InstantiationModelAwarePointcutAdvisorImpl這個方法是如何實例化advice的.
  • org.springframework.aop.aspectj.annotation.InstantiationModelAwarePointcutAdvisorImpl#InstantiationModelAwarePointcutAdvisorImpl
public InstantiationModelAwarePointcutAdvisorImpl(AspectJExpressionPointcut declaredPointcut,
        Method aspectJAdviceMethod, AspectJAdvisorFactory aspectJAdvisorFactory,
        MetadataAwareAspectInstanceFactory aspectInstanceFactory, int declarationOrder, String aspectName) {
    // 當(dāng)前的pointcut表達(dá)式
    this.declaredPointcut = declaredPointcut;
    // 切面Class
    this.declaringClass = aspectJAdviceMethod.getDeclaringClass();
    // advice方法名稱
    this.methodName = aspectJAdviceMethod.getName();
    // 方法參數(shù)類型
    this.parameterTypes = aspectJAdviceMethod.getParameterTypes();
    // 方法實例
    this.aspectJAdviceMethod = aspectJAdviceMethod;
    // aspectJ的advisor工廠
    this.aspectJAdvisorFactory = aspectJAdvisorFactory;
    // aspectJ實例工廠
    this.aspectInstanceFactory = aspectInstanceFactory;
    // 切面順序
    this.declarationOrder = declarationOrder;
    // 切面類名稱
    this.aspectName = aspectName;
    // 是否需要延時加載
    if (aspectInstanceFactory.getAspectMetadata().isLazilyInstantiated()) {
        // Static part of the pointcut is a lazy type.
        Pointcut preInstantiationPointcut = Pointcuts.union(
                aspectInstanceFactory.getAspectMetadata().getPerClausePointcut(), this.declaredPointcut);

        // Make it dynamic: must mutate from pre-instantiation to post-instantiation state.
        // If it's not a dynamic pointcut, it may be optimized out
        // by the Spring AOP infrastructure after the first evaluation.
        this.pointcut = new PerTargetInstantiationModelPointcut(
                this.declaredPointcut, preInstantiationPointcut, aspectInstanceFactory);
        this.lazy = true;
    }
    else {
        // A singleton aspect.
        // singleton模型的aspect
        this.pointcut = this.declaredPointcut;
        this.lazy = false;
        // 將切面中的advice進(jìn)行實例化
        this.instantiatedAdvice = instantiateAdvice(this.declaredPointcut);
    }
}
  1. InstantiationModelAwarePointcutAdvisorImpl是advisor的子類.在這個構(gòu)造函數(shù)內(nèi)對傳入的屬性進(jìn)行了設(shè)置,然后根據(jù)當(dāng)前的切面模型決定是否需要延遲加載.
  2. 通常我們的切面類都是singleton的,所有會直接執(zhí)行instantiateAdvice.
  • org.springframework.aop.aspectj.annotation.InstantiationModelAwarePointcutAdvisorImpl#instantiateAdvice
private Advice instantiateAdvice(AspectJExpressionPointcut pointcut) {
    Advice advice = this.aspectJAdvisorFactory.getAdvice(this.aspectJAdviceMethod, pointcut,
            this.aspectInstanceFactory, this.declarationOrder, this.aspectName);
    return (advice != null ? advice : EMPTY_ADVICE);
}

這里直接轉(zhuǎn)發(fā)給了this.aspectJAdvisorFactory.getAdvice這個方法.繼續(xù)跟蹤.

  • org.springframework.aop.aspectj.annotation.ReflectiveAspectJAdvisorFactory#getAdvice
public Advice getAdvice(Method candidateAdviceMethod, AspectJExpressionPointcut expressionPointcut,
        MetadataAwareAspectInstanceFactory aspectInstanceFactory, int declarationOrder, String aspectName) {
    // 獲取切面類Class
    Class<?> candidateAspectClass = aspectInstanceFactory.getAspectMetadata().getAspectClass();
    // 校驗合法性
    validate(candidateAspectClass);
    // 獲取切面方法上的注解
    AspectJAnnotation<?> aspectJAnnotation =
            AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(candidateAdviceMethod);
    if (aspectJAnnotation == null) {
        return null;
    }

    // If we get here, we know we have an AspectJ method.
    // Check that it's an AspectJ-annotated class
    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;
    // 使用switch來判斷當(dāng)前advice類型
    switch (aspectJAnnotation.getAnnotationType()) {
        // pointcut不解析
        case AtPointcut:
            if (logger.isDebugEnabled()) {
                logger.debug("Processing pointcut '" + candidateAdviceMethod.getName() + "'");
            }
            return null;
        // around類型的Advice
        case AtAround:
            springAdvice = new AspectJAroundAdvice(
                    candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
            break;
        // before類型的Advice
        case AtBefore:
            springAdvice = new AspectJMethodBeforeAdvice(
                    candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
            break;
        // after類型的Advice
        case AtAfter:
            springAdvice = new AspectJAfterAdvice(
                    candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
            break;
        // afterReturning類型的Advice
        case AtAfterReturning:
            springAdvice = new AspectJAfterReturningAdvice(
                    candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
            AfterReturning afterReturningAnnotation = (AfterReturning) aspectJAnnotation.getAnnotation();
            if (StringUtils.hasText(afterReturningAnnotation.returning())) {
                springAdvice.setReturningName(afterReturningAnnotation.returning());
            }
            break;
        // afterThrowing類型的Advice
        case AtAfterThrowing:
            springAdvice = new AspectJAfterThrowingAdvice(
                    candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
            AfterThrowing afterThrowingAnnotation = (AfterThrowing) aspectJAnnotation.getAnnotation();
            if (StringUtils.hasText(afterThrowingAnnotation.throwing())) {
                springAdvice.setThrowingName(afterThrowingAnnotation.throwing());
            }
            break;
        default:
            throw new UnsupportedOperationException(
                    "Unsupported advice type on method: " + candidateAdviceMethod);
    }

    // Now to configure the advice...
    // 設(shè)置AspectName、DeclarationOrder,為后期執(zhí)行調(diào)用鏈的時候做準(zhǔn)備
    springAdvice.setAspectName(aspectName);
    springAdvice.setDeclarationOrder(declarationOrder);
    String[] argNames = this.parameterNameDiscoverer.getParameterNames(candidateAdviceMethod);
    if (argNames != null) {
        springAdvice.setArgumentNamesFromStringArray(argNames);
    }
    springAdvice.calculateArgumentBindings();

    return springAdvice;
}
  1. 解析Advice之前,Spring又又又對切面類進(jìn)行了一次校驗.
  2. 解析Advice,根據(jù)當(dāng)前方法上的注解匹配對應(yīng)的advice.例如:around、before、after、afterReturning、afterThrowing.
  3. 為advice實例配置切面名稱、參數(shù)名稱、聲明順序等.

OK,至此,Advice實例就被解析成功了.此時的InstantiationModelAwarePointcutAdvisorImpl成員屬性中攜帶了pointcut+advice.

梳理加載Advisors的整體流程.

流程圖

擴(kuò)展閱讀

【小家Spring】Spring AOP中@Pointcut切入點(diǎn)表達(dá)式最全面使用介紹
【小家Spring】Spring AOP核心類Pointcut解析,對PointcutExpression切點(diǎn)表達(dá)式解析原理分析(以AspectJExpressionPointcut為例)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容