33--SpringAop獲取增強(一)

上一節(jié)分析了aspectj-autoproxy標簽的解析過程,并注冊了AnnotationAwareAspectJAutoProxyCreator。但是該類的作用是什么呢,看起來茫然無措,這時不妨查看一下類的繼承關系結構。

AnnotationAwareAspectJAutoProxyCreator類圖結構

從上圖可以看到,AnnotationAwareAspectJAutoProxyCreator類實現了BeanPostProcessor接口,讀過之前的章節(jié)或者對bean的生命周期有所了解的同學一定知道,在bean實例化完成之前和完成之后分別會自動BeanPostProcessor接口的postProcessBeforeInitialization和postProcessAfterInitialization方法。

依次打開AnnotationAwareAspectJAutoProxyCreator的父類,在AbstractAutoProxyCreator類里,找到postProcessBeforeInitialization方法和postProcessAfterInitialization方法,開始分析。

1. postProcessBeforeInstantiation方法
public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) {
    Object cacheKey = getCacheKey(beanClass, beanName);

    // 1、預處理判斷
    if (!StringUtils.hasLength(beanName) || !this.targetSourcedBeans.contains(beanName)) {
        // 判斷該類是否應被處理過
        if (this.advisedBeans.containsKey(cacheKey)) {
            return null;
        }
        // 判斷beanClass是否需要被代理
        // isInfrastructureClass-->判斷beanClass是否為AOP基礎類例如Advice(增強),Advisors(切面),Pointcut(切點)
        // shouldSkip-->判斷beanClass是否指定了不需要代理
        if (isInfrastructureClass(beanClass) || shouldSkip(beanClass, beanName)) {
            // 緩存找到的切面類信息
            this.advisedBeans.put(cacheKey, Boolean.FALSE); 
            return null;
        }
    }

    // Create proxy here if we have a custom TargetSource.
    // Suppresses unnecessary default instantiation of the target bean:
    // The TargetSource will handle target instances in a custom fashion.
    // 2、如果有自定義TargetSource的話,則在此創(chuàng)建代理
    /**
     *  自定義TargetSource示例:
     *  <bean class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
     *      <property name="customTargetSourceCreators">
     *          <list>
     *              <bean class="org.springframework.aop.framework.autoproxy.target.LazyInitTargetSourceCreator"/>        
     *          </list>
     *      </property>
     *  </bean>
     */
    TargetSource targetSource = getCustomTargetSource(beanClass, beanName);
    if (targetSource != null) {
        if (StringUtils.hasLength(beanName)) {
            this.targetSourcedBeans.add(beanName);
        }
        Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(beanClass, beanName, targetSource);
        Object proxy = createProxy(beanClass, beanName, specificInterceptors, targetSource);
        this.proxyTypes.put(cacheKey, proxy.getClass());
        return proxy;
    }
    return null;
}

postProcessBeforeInstantiation一共做了兩件事情

  1. 緩存切面類的信息
    先判斷對應的beanClass是否為Aop的基礎類,如果是的話,直接緩存。
    然后通過shouldSkip方法判斷beanClass是否需要被自動代理,如果不需要被自動代理的話,返回true,否則返回false。
  2. 判斷有無自定義TargetSource,如果有的話,則在此方法里創(chuàng)建代理
    關于自定義TargetSource已經給出了一個簡單的實例,感興趣的同學可以自己debug代碼。

其中第一步的shouldSkip(beanClass, beanName)方法,看似簡單,其實這里面包含了非常復雜的業(yè)務邏輯處理?!ぜ?strong>增強的提取

2. shouldSkip方法簡析
/**
 * 如果給定的bean不應該被認為是后處理器自動代理的,子類應該重寫這個方法以返回true。
 * @param beanClass the class of the bean
 * @param beanName the name of the bean
 * @return
 */
@Override
protected boolean shouldSkip(Class<?> beanClass, String beanName) {
    // TODO: Consider optimization by caching the list of the aspect names
    // 1、查找所有候選增強
    List<Advisor> candidateAdvisors = findCandidateAdvisors();
    // 2、循環(huán)判斷所有的增強,如果增強是AspectJPointcutAdvisor的實例
    //    并且其名稱與當前bean的名稱相同,則返回true,即該bean無需代理
    for (Advisor advisor : candidateAdvisors) {
        if (advisor instanceof AspectJPointcutAdvisor
                && ((AspectJPointcutAdvisor) advisor).getAspectName().equals(beanName)) {
            return true;
        }
    }
    return super.shouldSkip(beanClass, beanName);
}

該方法主邏輯很簡單,查找所有的候選增強并循環(huán)判斷當前beanName是否需要被代理,關鍵是findCandidateAdvisors()方法中獲取增強的過程。

/**
 * AnnotationAwareAspectJAutoProxyCreator
 * 查找所有候選增強方法
 * @return
 */
@Override
protected List<Advisor> findCandidateAdvisors() {
    // Add all the Spring advisors found according to superclass rules.
    // 1、從父類中獲取所有的增強
    List<Advisor> advisors = super.findCandidateAdvisors();
    // Build Advisors for all AspectJ aspects in the bean factory.
    // 2、從當前BeanFactory中查找所有標記了@AspectJ的注解的bean,并返回增強注解集合
    if (this.aspectJAdvisorsBuilder != null) {
        advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors());
    }
    return advisors;
}

該方法也非常簡單:

  • 從父類中獲取所有的增強
  • 從當前BeanFactory中查找所有標記了@AspectJ的注解的bean,并返回增強注解集合
    逐個對其進行分析:
3. findCandidateAdvisors方法分析
protected List<Advisor> findCandidateAdvisors() {
    return this.advisorRetrievalHelper.findAdvisorBeans();
}
/**
 * 從當前BeanFactory中尋找所有的增強bean,忽略FactoryBean和正在創(chuàng)建的bean
 * Find all eligible Advisor beans in the current bean factory,
 * ignoring FactoryBeans and excluding beans that are currently in creation.
 * @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.
    // 獲取緩存的增強
    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!
        // 從當前BeanFactory中獲取所有類型為Advisor的bean
        advisorNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
                this.beanFactory,
                Advisor.class,
                true,
                false);
        this.cachedAdvisorBeanNames = advisorNames;
    }
    // 當前BeanFactory中沒有類型為Advisor的bean則返回一個空的集合
    if (advisorNames.length == 0) {
        return new ArrayList<>();
    }

    // 循環(huán)所有獲取到的bean
    List<Advisor> advisors = new ArrayList<>();
    for (String name : advisorNames) {
        if (isEligibleBean(name)) {
            // 跳過正在創(chuàng)建的增強
            if (this.beanFactory.isCurrentlyInCreation(name)) {
                if (logger.isDebugEnabled()) {
                    logger.debug("Skipping currently created advisor '" + name + "'");
                }
            }
            else {
                try {
                    // 通過getBean方法獲取bean實例
                    advisors.add(this.beanFactory.getBean(name, Advisor.class));
                }
                catch (BeanCreationException ex) {
                    Throwable rootCause = ex.getMostSpecificCause();
                    if (rootCause instanceof BeanCurrentlyInCreationException) {
                        BeanCreationException bce = (BeanCreationException) rootCause;
                        String bceBeanName = bce.getBeanName();
                        if (bceBeanName != null && this.beanFactory.isCurrentlyInCreation(bceBeanName)) {
                            // 跳過正在創(chuàng)建的增強
                            if (logger.isDebugEnabled()) {
                                logger.debug("Skipping advisor '" + name +
                                        "' with dependency on currently created bean: " + ex.getMessage());
                            }
                            // Ignore: indicates a reference back to the bean we're trying to advise.
                            // We want to find advisors other than the currently created bean itself.
                            continue;
                        }
                    }
                    throw ex;
                }
            }
        }
    }
    return advisors;
}
4. buildAspectJAdvisors方法分析
/**
 * 在當前BeanFactory中查找AspectJ-annotated的注解信息,并返回增強集合
 * 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.
 * @return the list of {@link org.springframework.aop.Advisor} beans
 * @see #isEligibleBean
 */
public List<Advisor> buildAspectJAdvisors() {
    List<String> aspectNames = this.aspectBeanNames;

    // 1、提取增強
    if (aspectNames == null) {
        synchronized (this) {
            aspectNames = this.aspectBeanNames;
            if (aspectNames == null) {
                List<Advisor> advisors = new ArrayList<>();
                aspectNames = new ArrayList<>();
                // 1.1、獲取容器中的所有bean
                String[] beanNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
                        this.beanFactory, Object.class, true, false);
                // 1.2、循環(huán)所有的bean,并從切面類上提取增強
                for (String beanName : beanNames) {

                    // 判斷該beanName是否符合條件
                    // 如果配置文件指定了<aop:include/>屬性,那么只有符合表達式條件的切面類的增強才會被提取
                    // 例如:配置<aop:include name="dogAspect"></aop:include>
                    // 那么只有dogAspect切面類的增強才會被提取
                    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.
                    // 獲取beanType類型
                    Class<?> beanType = this.beanFactory.getType(beanName);
                    if (beanType == null) {
                        continue;
                    }
                    // 如果beanType是一個切面類
                    if (this.advisorFactory.isAspect(beanType)) {
                        aspectNames.add(beanName);
                        AspectMetadata amd = new AspectMetadata(beanType, beanName);
                        /**
                         * 切面實例化模型簡介
                         *
                         * singleton: 即切面只會有一個實例;
                         * perthis  : 每個切入點表達式匹配的連接點對應的AOP對象都會創(chuàng)建一個新切面實例;
                         *            使用@Aspect("perthis(切入點表達式)")指定切入點表達式;
                         *            例如: @Aspect("perthis(this(com.lyc.cn.v2.day04.aspectj.Dog))")
                         * pertarget: 每個切入點表達式匹配的連接點對應的目標對象都會創(chuàng)建一個新的切面實例;
                         *            使用@Aspect("pertarget(切入點表達式)")指定切入點表達式;
                         *            例如:
                         *
                         * 默認是singleton實例化模型,Schema風格只支持singleton實例化模型,而@AspectJ風格支持這三種實例化模型。
                         */
                        // singleton實例化模型處理
                        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);
                        }
                        // perthis或pertarget實例化模型處理
                        else {
                            /**
                             * 注意:當使用perthis或pertarget屬性時,切面類不能是單例bean,否則會拋出下面的異常
                             * 例如:<bean name="dogAspect" class="com.lyc.cn.v2.day04.aspectj.DogAspect" scope="singleton"/>
                             * 則會報錯,應該為
                             *      <bean name="dogAspect" class="com.lyc.cn.v2.day04.aspectj.DogAspect" scope="prototype"/>
                             */
                            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;
            }
        }
    }

    // 2、返回從緩存中獲取提取到的增強方法
    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;
}

其中的步驟在代碼里都標注的很清晰了,這里會涉及到一個切面實例化模型的概念,如果初看AOP的源碼,完全可以忽略該概念,把精力放在主線的分析上。其實該方法里大部分都是預處理、緩存、以及各種業(yè)務判斷,增強的提取工作交給了List<Advisor> classAdvisors = this.advisorFactory.getAdvisors(factory);。這也是我們要分析的重點。

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

相關閱讀更多精彩內容

友情鏈接更多精彩內容