【Spring註解驅動開發】AOP核心類解析,這是最全的一篇了!!

冰河團隊發表於2020-09-03

寫在前面

昨天二狗子讓我給他講@EnableAspectJAutoProxy註解,講到AnnotationAwareAspectJAutoProxyCreator類的原始碼時,二狗子消化不了了。這不,今天又來讓我給他講講AOP的核心類。那我們就開始吧!

關於 冰河技術 微信公眾號,後臺回覆 “Spring註解”領取原始碼工程。

如果文章對你有點幫助,麻煩點個贊,給個在看和轉發,大家的三連是對我持續創作最大的動力!!

類結構圖

我們先來看下AnnotationAwareAspectJAutoProxyCreator類的結構圖。

上圖中一些 類/介面 的介紹:

AspectJAwareAdvisorAutoProxyCreator : 公開了AspectJ的呼叫上下文,並弄清楚來自同一切面的多個Advisor在AspectJ中的優先順序規則。

AbstractAdvisorAutoProxyCreator : 通用自動代理建立器,它基於檢測到的每個顧問程式為特定bean構建AOP代理。

AbstractAutoProxyCreator : 擴充套件了 ProxyProcessorSupport,實現了SmartInstantiationAwareBeanPostProcessor、BeanFactoryAware 介面,是BeanPostProcessor 實現,該實現使用AOP代理包裝每個合格的bean,並在呼叫bean本身之前委派給指定的攔截器。

BeanFactoryAware : 實現了該介面的Bean可以知道它屬於那個 BeanFactory,Bean可以通過Spring容器查詢它的協同者(依賴查詢),但大多數的Bean是通過構造器引數和Bean方法(依賴注入)來獲取它的協同者。

BeanPostProcessor :工廠鉤子,允許自定義修改新的bean例項。例如,檢查標記介面或使用代理包裝bean。如果我們需要在Spring容器中完成Bean的例項化,配置和其初始化前後新增一些自己的邏輯處理,我們就可以定義一個或多個BeanPostProcessor介面的實現,然後註冊到容器中。

InstantiationAwareBeanPostProcessor : BeanPostProcessor 的子介面,它新增了例項化之前的回撥,以及例項化之後但設定了顯式屬性或自動裝配之前的回撥。它內部提供了3個方法,再加上BeanPostProcessor介面內部的2個方法,實現這個介面需要實現5個方法。InstantiationAwareBeanPostProcessor 介面的主要作用在於目標物件的例項化過程中需要處理的事情,包括例項化物件的前後過程以及例項的屬性設定。

SmartInstantiationAwareBeanPostProcessor : InstantiationAwareBeanPostProcessor 介面的擴充套件,多出了3個方法,新增了用於預測已處理bean的最終型別的回撥,再加上父介面的5個方法,所以實現這個介面需要實現8個方法,主要作用也是在於目標物件的例項化過程中需要處理的事情。

總之: AspectJAwareAdvisorAutoProxyCreator為 AspectJ 切面類建立自動代理。

核心類解析

BeanPostProcessor 介面中的兩個方法 postProcessBeforeInitialization 和 postProcessAfterInitialization,作用是對Bean初始化前後新增一些自己的邏輯。

@Nullable
default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
    return bean;
}

@Nullable
default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
    return bean;
}

InstantiationAwareBeanPostProcessorBeanPostProcessor 的子介面,它額外增加了3個新的方法:postProcessBeforeInstantiation( 目標物件被例項化之前呼叫的方法,可以返回目標例項的一個代理用來代替目標例項 )、postProcessAfterInstantiation(該方法在Bean例項化之後執行,返回false,會忽略屬性值的設定;如果返回true,會按照正常流程設定屬性值) 和 postProcessPropertyValues(對屬性值進行修改,未來版本將會刪除)

@Nullable
default Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
    return null;
}

default boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
    return true;
}

@Nullable
default PropertyValues postProcessPropertyValues(
    PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeansException {
    return pvs;
}

SmartInstantiationAwareBeanPostProcessor介面繼承InstantiationAwareBeanPostProcessor介面,裡面定義了3個方法:predictBeanType(預測Bean的型別)、determineCandidateConstructors(選擇合適的構造器)、getEarlyBeanReference(解決迴圈引用問題)。

@Nullable
default Class<?> predictBeanType(Class<?> beanClass, String beanName) throws BeansException {
    return null;
}

@Nullable
default Constructor<?>[] determineCandidateConstructors(Class<?> beanClass, String beanName) throws BeansException {
    return null;
}

default Object getEarlyBeanReference(Object bean, String beanName) throws BeansException {
    return bean;
}

AbstractAutoProxyCreator 是AOP的一個核心類,它實現了SmartInstantiationAwareBeanPostProcessor、BeanFactoryAware 介面,實現了代理建立的邏輯,使用AOP代理包裝每個合格的bean,並在呼叫bean本身之前委派給指定的攔截器。

AbstractAdvisorAutoProxyCreator 通用自動代理建立器,它基於檢測每個bean的增強器,為特殊的bean構建AOP代理。子類可以重寫此findCandidateAdvisors()方法,以返回適用於任何物件的advisor的自定義列表,子類還可以重寫繼承的AbstractAutoProxyCreator.shouldSkip()方法,以將某些物件排除在自動代理之外。

protected List<Advisor> findCandidateAdvisors() {
       Assert.state(this.advisorRetrievalHelper != null, "No BeanFactoryAdvisorRetrievalHelper available");
     return this.advisorRetrievalHelper.findAdvisorBeans();
}

AspectJAwareAdvisorAutoProxyCreator 擴充套件 AbstractAdvisorAutoProxyCreator,公開了AspectJ的呼叫上下文,並在多個增強器來自同一切面時搞清楚AspectJ的建議優先順序順序。按AspectJ優先順序排序其餘部分:

@Override
@SuppressWarnings("unchecked")
protected List<Advisor> sortAdvisors(List<Advisor> advisors) {
    List<PartiallyComparableAdvisorHolder> partiallyComparableAdvisors = new ArrayList<>(advisors.size());
    for (Advisor element : advisors) {
        partiallyComparableAdvisors.add(
            new PartiallyComparableAdvisorHolder(element, DEFAULT_PRECEDENCE_COMPARATOR));
    }
    List<PartiallyComparableAdvisorHolder> sorted = PartialOrder.sort(partiallyComparableAdvisors);
    if (sorted != null) {
        List<Advisor> result = new ArrayList<>(advisors.size());
        for (PartiallyComparableAdvisorHolder pcAdvisor : sorted) {
            result.add(pcAdvisor.getAdvisor());
        }
        return result;
    }
    else {
        return super.sortAdvisors(advisors);
    }
}

在增強鏈頭部增加一個ExposeInvocationInterceptor,使用AspectJ表示式切入點和使用AspectJ樣式的advisor時,需要這些附加advisor。

protected void extendAdvisors(List<Advisor> candidateAdvisors) {
      AspectJProxyUtils.makeAdvisorChainAspectJCapableIfNecessary(candidateAdvisors);
}

如果此後處理器不應該考慮將給定的bean用於自動代理,子類應重寫此方法以返回true

@Override
protected boolean shouldSkip(Class<?> beanClass, String beanName) {
    // TODO: Consider optimization by caching the list of the aspect names
    List<Advisor> candidateAdvisors = findCandidateAdvisors();
    for (Advisor advisor : candidateAdvisors) {
        if (advisor instanceof AspectJPointcutAdvisor &&
            ((AspectJPointcutAdvisor) advisor).getAspectName().equals(beanName)) {
            return true;
        }
    }
    return super.shouldSkip(beanClass, beanName);
}

AspectJAwareAdvisorAutoProxyCreator 還有一個子類叫 AnnotationAwareAspectJAutoProxyCreator,子類AnnotationAwareAspectJAutoProxyCreator是用於處理當前應用程式上下文中的所有AspectJ註釋方面以及Spring Advisor。如果Spring AOP的基於代理的模型能夠應用任何AspectJ註釋的類,它們的advisor將被自動識別,這涵蓋了方法執行連線點,Spring Advisor的處理遵循AbstractAdvisorAutoProxyCreator中建立的規則。

生成代理物件

從使用aop:xxx標籤來自動生成代理的話,先看看AopNamespaceHandler,使用aop:config標籤則使用 ConfigBeanDefinitionParser 解析,使用了aop:aspectj-autoproxy標籤則使用 AspectJAutoProxyBeanDefinitionParser 解析,依次類推。

@Override
public void init() {
    // In 2.0 XSD as well as in 2.1 XSD.
    registerBeanDefinitionParser("config", new ConfigBeanDefinitionParser());
    registerBeanDefinitionParser("aspectj-autoproxy", new AspectJAutoProxyBeanDefinitionParser());
    registerBeanDefinitionDecorator("scoped-proxy", new ScopedProxyBeanDefinitionDecorator());

    // Only in 2.0 XSD: moved to context namespace as of 2.1
    registerBeanDefinitionParser("spring-configured", new SpringConfiguredBeanDefinitionParser());
}

ConfigBeanDefinitionParser.java

@Override
@Nullable
public BeanDefinition parse(Element element, ParserContext parserContext) {
    CompositeComponentDefinition compositeDef =
        new CompositeComponentDefinition(element.getTagName(), parserContext.extractSource(element));
    parserContext.pushContainingComponent(compositeDef);

    configureAutoProxyCreator(parserContext, element); // 註冊AspectJAwareAdvisorAutoProxyCreator

    List<Element> childElts = DomUtils.getChildElements(element);
    for (Element elt: childElts) {
        String localName = parserContext.getDelegate().getLocalName(elt);
        if (POINTCUT.equals(localName)) {
            parsePointcut(elt, parserContext);
        }
        else if (ADVISOR.equals(localName)) {
            parseAdvisor(elt, parserContext);
        }
        else if (ASPECT.equals(localName)) {
            parseAspect(elt, parserContext);
        }
    }

    parserContext.popAndRegisterContainingComponent();
    return null;
}

private void configureAutoProxyCreator(ParserContext parserContext, Element element) {
    AopNamespaceUtils.registerAspectJAutoProxyCreatorIfNecessary(parserContext, element);
}

AopConfigUtils.java

@Override
@Nullable
public BeanDefinition parse(Element element, ParserContext parserContext) {
    CompositeComponentDefinition compositeDef =
        new CompositeComponentDefinition(element.getTagName(), parserContext.extractSource(element));
    parserContext.pushContainingComponent(compositeDef);

    configureAutoProxyCreator(parserContext, element); // 註冊AspectJAwareAdvisorAutoProxyCreator

    List<Element> childElts = DomUtils.getChildElements(element);
    for (Element elt: childElts) {
        String localName = parserContext.getDelegate().getLocalName(elt);
        if (POINTCUT.equals(localName)) {
            parsePointcut(elt, parserContext);
        }
        else if (ADVISOR.equals(localName)) {
            parseAdvisor(elt, parserContext);
        }
        else if (ASPECT.equals(localName)) {
            parseAspect(elt, parserContext);
        }
    }

    parserContext.popAndRegisterContainingComponent();
    return null;
}

private void configureAutoProxyCreator(ParserContext parserContext, Element element) {
    AopNamespaceUtils.registerAspectJAutoProxyCreatorIfNecessary(parserContext, element);
}

AopConfigUtils.java

public static void registerAspectJAutoProxyCreatorIfNecessary(
    ParserContext parserContext, Element sourceElement) {
    // 在這裡註冊的是AspectJAwareAdvisorAutoProxyCreator
    BeanDefinition beanDefinition = AopConfigUtils.registerAspectJAutoProxyCreatorIfNecessary(
        parserContext.getRegistry(), parserContext.extractSource(sourceElement));
    useClassProxyingIfNecessary(parserContext.getRegistry(), sourceElement);
    registerComponentIfNecessary(beanDefinition, parserContext); // 註冊元件
}
@Nullable
public static BeanDefinition registerAspectJAutoProxyCreatorIfNecessary(
    BeanDefinitionRegistry registry, @Nullable Object source) {

    return registerOrEscalateApcAsRequired(AspectJAwareAdvisorAutoProxyCreator.class, registry, source);
}

AspectJAwareAdvisorAutoProxyCreator 實現了 BeanPostProcessor 等上面介紹的介面,主要作用於Bean初始化前後,例項化前後,所有的Bean都被作用到。InstantiationAwareBeanPostProcessorBeanPostProcessor的子介面,但它的呼叫時間點發生在Bean例項化前,在真正呼叫doCreateBean()建立bean例項之前執行postProcessBeforeInstantiation()。

AbstractAutoProxyCreator.java

@Override
public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
    Object cacheKey = getCacheKey(beanClass, beanName);  // 得到一個快取的唯一key(根據beanClass和beanName生成唯一key)
    // 如果當前targetSourcedBeans(通過自定義TargetSourceCreator建立的TargetSource)不包含cacheKey
    if (!StringUtils.hasLength(beanName) || !this.targetSourcedBeans.contains(beanName)) {
        if (this.advisedBeans.containsKey(cacheKey)) {  //advisedBeans(已經被增強的Bean,即AOP代理物件)中包含當前cacheKey,返回null,即走Spring預設流程
            return null;
        }
        if (isInfrastructureClass(beanClass) || shouldSkip(beanClass, beanName)) {// 如果是基礎設施類(如Advisor、Advice、AopInfrastructureBean的實現)不進行處理;(略)
            this.advisedBeans.put(cacheKey, Boolean.FALSE);
            return null;
        }
    }

    // 如果有自定義的TargetSource,在此處建立代理
    // 禁止目標Bean的不必要的預設例項化:
    // TargetSource將以自定義方式處理目標例項。
    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;
}

通過 AbstractAutoProxyCreator 中的 postProcessAfterInitialization() 建立AOP代理。

@Override
public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) throws BeansException {
    if (bean != null) {
        Object cacheKey = getCacheKey(bean.getClass(), beanName);
        if (!this.earlyProxyReferences.contains(cacheKey)) {  // 如果之前呼叫過getEarlyBeanReference獲取包裝目標物件到AOP代理物件(如果需要),則不再執行
            return wrapIfNecessary(bean, beanName, cacheKey);  // 包裝目標物件到AOP代理物件(如果需要)
        }
    }
    return bean;
}

protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
    if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) { // 通過TargetSourceCreator進行自定義TargetSource不需要包裝
        return bean;
    }
    if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {  // 不應該被增強物件不需要包裝
        return bean;
    }
    if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) { // 基礎設施或應該skip的不需要保證
        this.advisedBeans.put(cacheKey, Boolean.FALSE);
        return bean;
    }

    // 如果有advise則建立代理。
    Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
    if (specificInterceptors != DO_NOT_PROXY) {
        this.advisedBeans.put(cacheKey, Boolean.TRUE);
        Object proxy = createProxy(
            bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean)); // 建立代理物件
        this.proxyTypes.put(cacheKey, proxy.getClass());
        return proxy;
    }

    this.advisedBeans.put(cacheKey, Boolean.FALSE);
    return bean;
}

重磅福利

關注「 冰河技術 」微信公眾號,後臺回覆 “設計模式” 關鍵字領取《深入淺出Java 23種設計模式》PDF文件。回覆“Java8”關鍵字領取《Java8新特性教程》PDF文件。回覆“限流”關鍵字獲取《億級流量下的分散式限流解決方案》PDF文件,三本PDF均是由冰河原創並整理的超硬核教程,面試必備!!

好了,今天就聊到這兒吧!別忘了點個贊,給個在看和轉發,讓更多的人看到,一起學習,一起進步!!

寫在最後

如果你覺得冰河寫的還不錯,請微信搜尋並關注「 冰河技術 」微信公眾號,跟冰河學習高併發、分散式、微服務、大資料、網際網路和雲原生技術,「 冰河技術 」微信公眾號更新了大量技術專題,每一篇技術文章乾貨滿滿!不少讀者已經通過閱讀「 冰河技術 」微信公眾號文章,吊打面試官,成功跳槽到大廠;也有不少讀者實現了技術上的飛躍,成為公司的技術骨幹!如果你也想像他們一樣提升自己的能力,實現技術能力的飛躍,進大廠,升職加薪,那就關注「 冰河技術 」微信公眾號吧,每天更新超硬核技術乾貨,讓你對如何提升技術能力不再迷茫!

相關文章