[Spring]AnnotationAwareAspectJAutoProxyCreator-@AspectJ的解析器

AnnotationAwareAspectJAutoProxyCreator職能

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

UML

UML

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

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

Spring Advisor

Spring中的Advisor接口是Spring AOP的基礎(chǔ)接口裹刮,一個(gè)Advisor可以持有一個(gè)pointcut和一個(gè)AOP advice.Spring AOP正是通過(guò)將被AspectJ標(biāo)注的類中的不同Advice解析成Advisor調(diào)用鏈來(lái)執(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);

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

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

    // 設(shè)置代理是否應(yīng)由AOP框架公開(kāi)為T(mén)hreadLocal以便通過(guò)AopContext類進(jìn)行檢索霜第。
    // 默認(rèn)值為false,以實(shí)現(xiàn)最佳性能户辞。
    void setExposeProxy(boolean exposeProxy);

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

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

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

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

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

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

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

    // 替代某個(gè)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代理的配置項(xiàng)泌类。
    String toProxyConfigString();

}

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

TargetSource

Spring AOP并不是直接代理目標(biāo)類,而是通過(guò)代理TargetSource接口進(jìn)而實(shí)現(xiàn)動(dòng)態(tài)代理.
簡(jiǎn)單來(lái)說(shuō)即: Spring AOP->TargetSource->targetObject

  • UML
targetSource

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

加載切面類并解析advisor

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

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

        // 如果當(dāng)前beanClass存在用戶自定義的TargetSource,則進(jìn)行代理
        // 在Spring AOP中苞轿,動(dòng)態(tài)代理并不是直接代理target對(duì)象的茅诱,而是通過(guò)代理TargetSource來(lái)間接代理target對(duì)象
        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. 需要過(guò)濾已經(jīng)創(chuàng)建過(guò)動(dòng)態(tài)代理的類,advisedBeans這個(gè)Map便是緩存已經(jīng)被Spring AOP處理過(guò)的BeanClass.
  2. 其中isInfrastructureClass會(huì)過(guò)濾掉Spring AOP框架內(nèi)部的基類搬卒,同時(shí)會(huì)識(shí)別當(dāng)前是否標(biāo)注了@AspectJ與被ajc編譯器所編譯.
  3. 如果當(dāng)前用戶自定義實(shí)現(xiàn)了TargetSource接口,那么AbstractAutoProxyCreator會(huì)為用戶自定義的TargetSource創(chuàng)建代理.

我們深入isInfrastructureClass這個(gè)方法看看,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個(gè)判斷:

  1. 調(diào)用父類的isInfrastructureClass,返回true則直接中斷.
    父類執(zhí)行isInfrastructureClass的邏輯為:當(dāng)前beanClass是否實(shí)現(xiàn)Advice瑟俭、PointcutAdvisor契邀、AopInfrastructureBean.
  2. 判斷當(dāng)前beanClass是否為切面類.isApsect的邏輯比較簡(jiǎn)單:beanClass上是否標(biāo)注了@Aspect注解并且沒(méi)有被ajc編譯器編譯過(guò).
  • org.springframework.aop.aspectj.annotation.AbstractAspectJAdvisorFactory#isAspect
    public boolean isAspect(Class<?> clazz) {
        // 類上是否標(biāo)注@Aspect并且沒(méi)有被ajc編譯器編譯過(guò)
        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會(huì)在每次執(zhí)行postProcessBeforeInstantiation的時(shí)候,解析每個(gè)advisor,解析完成后將advisors進(jìn)行緩存坯门,進(jìn)而判斷當(dāng)前的beanClass和beanName是否已經(jīng)解析完畢. 下面微饥,我們來(lái)看看findCandidateAdvisors這個(gè)方法做了什么,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.從層級(jí)關(guān)系我們可以知道,
    // AspectJAwareAdvisorAutoProxyCreator提供對(duì)XML或者實(shí)現(xiàn)接口的AOP配置解析
    List<Advisor> advisors = super.findCandidateAdvisors();
    // Build Advisors for all AspectJ aspects in the bean factory.
    if (this.aspectJAdvisorsBuilder != null) {
        // 注解驅(qū)動(dòng)的AOP切面解析類解析
        advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors());
    }
    return advisors;
}

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

  1. 調(diào)用父類AspectJAwareAdvisorAutoProxyCreator#finCandidateAdvisors提供對(duì)XML或者實(shí)現(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)行了一個(gè)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>
 * 對(duì)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!
        // 如果緩存中沒(méi)有,那么從容器中以及其父容器中分析得到所有的advisor bean的名稱
        // BeanFactoryUtils.beanNamesForTypeIncludingAncestors此處是找到類型為advisor的bean
        // 注意,spring不推薦在此處實(shí)例化factoryBeans,因?yàn)閟pring需要保留所有未初始化的常規(guī)類
        // 以使自動(dòng)代理創(chuàng)建者對(duì)其應(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,提供給用戶自定義實(shí)現(xiàn),默認(rèn)返回true
        if (isEligibleBean(name)) {
            // 創(chuàng)建中的bean會(huì)被忽略简软,beanPostProcessor是每次加載bean都會(huì)觸發(fā)的鉤子
            // 所以在下次進(jìn)來(lái)時(shí),可能當(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實(shí)例
                    advisors.add(this.beanFactory.getBean(name, Advisor.class));
                }
                catch (BeanCreationException ex) {
                    // 省略處理異常細(xì)節(jié)
                }
            }
        }
    }
    return advisors;
}

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

遍歷advisorNames數(shù)組,對(duì)符合條件的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ā)訪問(wèn)
        synchronized (this) {
            aspectNames = this.aspectBeanNames;
            if (aspectNames == null) {
                List<Advisor> advisors = new ArrayList<>();
                // 保存切面名稱的集合
                aspectNames = new ArrayList<>();
                // 獲取所有的beanName
                // BeanFactoryUtils.beanNamesForTypeIncludingAncestors傳入的type為Object
                // 也就說(shuō)查找所有的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.
                    // 必須小心,不要急于實(shí)例化bean赠法,因?yàn)樵谶@種情況下麦轰,它們將由Spring容器緩存,但不會(huì)被編織。
                    // 獲取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這個(gè)緩存中
                        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可以組成一個(gè)個(gè)advisor
                            // 舉個(gè)例子款侵,before末荐、after、around每個(gè)都會(huì)搭配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;
}

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

  1. 嘗試從緩存獲取所有的aspectNames集合.如果緩存找不到,重新加載.執(zhí)行的方法又是BeanFactoryUtils.beanNamesForTypeIncludingAncestors妹笆,只不過(guò)這次傳入的類型是Object.class,也就是說(shuō)剃幌,獲取的是所有的beanNames.
  2. 遍歷beanNames數(shù)組,通過(guò)name獲取type,然后判斷當(dāng)前類是否為Aspect.也就是被@Aspect注解所標(biāo)記.
  3. 如果是Aspect,構(gòu)建AspectMetadata,AspectMetadata中保存了AjType,這是AspectJ框架的產(chǎn)物晾浴,通過(guò)它可以快速獲取當(dāng)前類的pointcutadvice等.Spring AOP正是借助AspectJ來(lái)獲取切面類的信息的.此外负乡,AspectJ還提供了很多切面模型種類,通常脊凰,我們的切面類都是為singleton-單例.
  4. 調(diào)用ReflectiveAspectJAdvisorFactory#getAdvisors來(lái)解析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();
    // 校驗(yàn)切面類,不可以為抽象類,需標(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
    // 包裝器類重寫(xiě)了getAspectInstance方法,并且保證當(dāng)前的factory在使用時(shí)才進(jìn)行加載(緩存)
    // 正如名字的意義一般 lazy singleton instance
    MetadataAwareAspectInstanceFactory lazySingletonAspectInstanceFactory =
            new LazySingletonAspectInstanceFactoryDecorator(aspectInstanceFactory);

    List<Advisor> advisors = new ArrayList<>();
    // 獲取aspect切面類中的所有方法,會(huì)過(guò)濾掉被@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)而獲取切面類型和切面名稱,隨后對(duì)切面類進(jìn)行校驗(yàn)-切面類不可以為抽象類,需標(biāo)記@Aspect,同時(shí),spring aop 不支持percflow狸涌、percflowbelow種類的aspect.
  2. 使用裝飾器模式包裝MetadataAwareAspectInstanceFactory來(lái)懶加載切面類實(shí)例.
  3. 獲取當(dāng)前類中標(biāo)記@Pointcut注解外所有的Method集合切省,獲取到的List<Method>按照Around, Before, After, AfterReturning, AfterThrowing的順序排序.
  4. 遍歷每一個(gè)Method,將符合條件的方法解析成advisor實(shí)例.
  5. 檢查是否有屬于introduction的成員,如果有便進(jìn)行解析(@DeclareParents).
  6. 將解析完成的每一個(gè)advisor添加到返回的結(jié)果集中.
  • org.springframework.aop.aspectj.annotation.ReflectiveAspectJAdvisorFactory#getAdvisor
@Override
@Nullable
public Advisor getAdvisor(Method candidateAdviceMethod, MetadataAwareAspectInstanceFactory aspectInstanceFactory,
        int declarationOrderInAspect, String aspectName) {
    // 驗(yàn)證aspectClass的合法性
    validate(aspectInstanceFactory.getAspectMetadata().getAspectClass());
    // 在切面的方法上構(gòu)建pointcut表達(dá)式
    AspectJExpressionPointcut expressionPointcut = getPointcut(
            candidateAdviceMethod, aspectInstanceFactory.getAspectMetadata().getAspectClass());
    if (expressionPointcut == null) {
        return null;
    }
    // 實(shí)例化切面中的advice對(duì)象
    return new InstantiationModelAwarePointcutAdvisorImpl(expressionPointcut, candidateAdviceMethod,
            this, aspectInstanceFactory, declarationOrderInAspect, aspectName);
}
  1. 校驗(yàn)aspectClass的合法性帕胆,這個(gè)validate是復(fù)用的朝捆,跟上述的方法一致,邏輯就不重復(fù)講了.
  2. 根據(jù)當(dāng)前的adviceMethod與aspectClass構(gòu)建出AspectJExpressionPointcut實(shí)例.它是一個(gè)pointcut表達(dá)式的實(shí)例.里面對(duì)AspectJ框架的表達(dá)式原語(yǔ)進(jìn)行了部分的支持(11種).
  3. 通過(guò)getPointcut()獲取到切點(diǎn)表達(dá)式之后,接下來(lái)就可以實(shí)例化adivce然后構(gòu)建出advisor了懒豹,因?yàn)橐粋€(gè)advisor = pointcut+advice.我們接著看InstantiationModelAwarePointcutAdvisorImpl這個(gè)方法是如何實(shí)例化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();
    // 方法實(shí)例
    this.aspectJAdviceMethod = aspectJAdviceMethod;
    // aspectJ的advisor工廠
    this.aspectJAdvisorFactory = aspectJAdvisorFactory;
    // aspectJ實(shí)例工廠
    this.aspectInstanceFactory = aspectInstanceFactory;
    // 切面順序
    this.declarationOrder = declarationOrder;
    // 切面類名稱
    this.aspectName = aspectName;
    // 是否需要延時(shí)加載
    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)行實(shí)例化
        this.instantiatedAdvice = instantiateAdvice(this.declaredPointcut);
    }
}
  1. InstantiationModelAwarePointcutAdvisorImpl是advisor的子類.在這個(gè)構(gòu)造函數(shù)內(nèi)對(duì)傳入的屬性進(jìn)行了設(shè)置芙盘,然后根據(jù)當(dāng)前的切面模型決定是否需要延遲加載.
  2. 通常我們的切面類都是singleton的,所有會(huì)直接執(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這個(gè)方法.繼續(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();
    // 校驗(yàn)合法性
    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來(lái)判斷當(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)用鏈的時(shí)候做準(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又又又對(duì)切面類進(jìn)行了一次校驗(yàn).
  2. 解析Advice,根據(jù)當(dāng)前方法上的注解匹配對(duì)應(yīng)的advice.例如:around记餐、before驮樊、after、afterReturning片酝、afterThrowing.
  3. 為advice實(shí)例配置切面名稱囚衔、參數(shù)名稱、聲明順序等.

OK雕沿,至此练湿,Advice實(shí)例就被解析成功了.此時(shí)的InstantiationModelAwarePointcutAdvisorImpl成員屬性中攜帶了pointcut+advice.

梳理加載Advisors的整體流程.

流程圖

擴(kuò)展閱讀

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

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末晦炊,一起剝皮案震驚了整個(gè)濱河市鞠鲜,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌断国,老刑警劉巖贤姆,帶你破解...
    沈念sama閱讀 217,907評(píng)論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異稳衬,居然都是意外死亡霞捡,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,987評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門(mén)薄疚,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)碧信,“玉大人,你說(shuō)我怎么就攤上這事街夭∨椴辏” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 164,298評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵板丽,是天一觀的道長(zhǎng)呈枉。 經(jīng)常有香客問(wèn)我,道長(zhǎng)埃碱,這世上最難降的妖魔是什么猖辫? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,586評(píng)論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮砚殿,結(jié)果婚禮上啃憎,老公的妹妹穿的比我還像新娘。我一直安慰自己似炎,他們只是感情好辛萍,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,633評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著羡藐,像睡著了一般叹阔。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上传睹,一...
    開(kāi)封第一講書(shū)人閱讀 51,488評(píng)論 1 302
  • 那天耳幢,我揣著相機(jī)與錄音,去河邊找鬼欧啤。 笑死睛藻,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的邢隧。 我是一名探鬼主播店印,決...
    沈念sama閱讀 40,275評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼倒慧!你這毒婦竟也來(lái)了按摘?” 一聲冷哼從身側(cè)響起包券,我...
    開(kāi)封第一講書(shū)人閱讀 39,176評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎炫贤,沒(méi)想到半個(gè)月后溅固,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,619評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡兰珍,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,819評(píng)論 3 336
  • 正文 我和宋清朗相戀三年侍郭,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片掠河。...
    茶點(diǎn)故事閱讀 39,932評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡亮元,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出唠摹,到底是詐尸還是另有隱情爆捞,我是刑警寧澤,帶...
    沈念sama閱讀 35,655評(píng)論 5 346
  • 正文 年R本政府宣布勾拉,位于F島的核電站嵌削,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏望艺。R本人自食惡果不足惜苛秕,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,265評(píng)論 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望找默。 院中可真熱鬧艇劫,春花似錦、人聲如沸惩激。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,871評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)风钻。三九已至顷蟀,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間骡技,已是汗流浹背鸣个。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,994評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留布朦,地道東北人囤萤。 一個(gè)月前我還...
    沈念sama閱讀 48,095評(píng)論 3 370
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像是趴,于是被迫代替她去往敵國(guó)和親涛舍。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,884評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容