Spring深度源碼解析(八)Spring AOP源碼分析

Spring AOP

在上一章節(jié),筆者對(duì)Spring-Mybatis的核心思想做了詳細(xì)介紹,目的是讓讀者能夠更加清晰的認(rèn)知Spring的全局生命周期,以及Spring是如何設(shè)計(jì)對(duì)外擴(kuò)展的開(kāi)放,本章將對(duì)Spring AOP的原理及源碼進(jìn)行詳細(xì)說(shuō)明。

Spring AOP應(yīng)用

首先還是對(duì)Spring AOP的基本功能簡(jiǎn)單介紹。切面配置類


image

被增強(qiáng)的類


image

配置類

image

新建一個(gè)測(cè)試類


image

輸出結(jié)果:


image

通過(guò)執(zhí)行結(jié)果我們可以看到我們不需要修改任何原有的代碼就可以改變代碼的邏輯,其實(shí)在上一篇文章中筆者就已經(jīng)對(duì)動(dòng)態(tài)代理有所介紹,比如在Mybatis中的Mapper接口就是通過(guò)JDK動(dòng)態(tài)代理,只不過(guò)我們的Mybatis代理需求相對(duì)復(fù)雜,而Spring AOP相對(duì)單一,因?yàn)镾pring AOP是對(duì)自己內(nèi)部的對(duì)象代理,也就是說(shuō)Spring AOP是先裝入Spring容器,在由其他的其他組件進(jìn)行代理,而Mybatis和其恰好消防,Mybatis是先代理在裝入Spring,所以我們?cè)谏弦黄恼轮性趯⒋韺?duì)象整合到Spring中遇到了很多問(wèn)題,如果讀者對(duì)此沒(méi)有印象建議回顧《Spring深度源碼解析(七) Spring-Mybatis核心思想》。

Spring AOP源碼解析

在對(duì)Spring應(yīng)用做了簡(jiǎn)單介紹后,我們先思考一下如果我們自己實(shí)現(xiàn)一個(gè)SpringAOP,如何去實(shí)現(xiàn)呢,如何動(dòng)態(tài)的去改變類的創(chuàng)建方式呢?在《Spring源碼深度分析(六)》筆者提到,在對(duì)Spring實(shí)例化前后、初始化前后,Spring都做了循環(huán)后置處理器的處理提供對(duì)外擴(kuò)展,再思考如果我們是對(duì)類進(jìn)行代理,那么會(huì)采用CGLIB的方式進(jìn)行代理,為什么SpringAOP實(shí)現(xiàn)了切面代理,我們關(guān)注這個(gè)注解

image

進(jìn)入這個(gè)注解

image

可以看到這里又有這個(gè)@Import注解,@Import什么用我就不介紹了,筆者在Spring-Mybatis做了大量文章。

image

這里我們又看到了ImportBeanDefinitionRegistrar,這里我在啰嗦幾句Spring提供了很多種對(duì)外的拓展方式,ImportBeanDefinitionRegistrar就是其中一種,如果自己定的類實(shí)現(xiàn)了它就可以獲取工廠注冊(cè)器。


@Override
  public void registerBeanDefinitions(
      AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {

    AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);

    AnnotationAttributes enableAspectJAutoProxy =
        AnnotationConfigUtils.attributesFor(importingClassMetadata, EnableAspectJAutoProxy.class);
    if (enableAspectJAutoProxy != null) {
      if (enableAspectJAutoProxy.getBoolean("proxyTargetClass")) {
        AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
      }
      if (enableAspectJAutoProxy.getBoolean("exposeProxy")) {
        AopConfigUtils.forceAutoProxyCreatorToExposeProxy(registry);
      }
    }

注意這段代碼:

AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);
->registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry, null);
->registerOrEscalateApcAsRequired(AnnotationAwareAspectJAutoProxyCreator.class, registry, source);
->registry.registerBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME, beanDefinition);

其實(shí)就是向我們的工廠注冊(cè)了這個(gè)一個(gè)類AnnotationAwareAspectJAutoProxyCreator,我們點(diǎn)開(kāi)這么類

image

可以看到這個(gè)類實(shí)現(xiàn)了BeanPostProcessor,說(shuō)明這個(gè)類同樣是后置處理器,既然這是后置處理器,就可以改變我們工廠內(nèi)部的對(duì)象,既然能夠改變我們的對(duì)象是不是就能將我們的某些對(duì)象進(jìn)行代理?答案是肯定的,那么這就解惑了我在上文提出的Spring通過(guò)什么手段完成的代理,讀者是不是覺(jué)得Spring的后置處理器很神奇啊,到哪都有它,好了我們對(duì)AnnotationAwareAspectJAutoProxyCreator做了簡(jiǎn)要分析,接下來(lái)將對(duì)Spring AOP做詳細(xì)介紹。Spring AOP源碼

首先我們將代碼停留在doCreateBean(),斷點(diǎn)采用的是被AOP增強(qiáng)的person類

image

然后這里的instanceWrapper為空,我們下一步,

image

看到我們的person對(duì)象已經(jīng)創(chuàng)建成功,注意我們發(fā)現(xiàn)這里的person對(duì)象并沒(méi)有被代理,而僅僅是被創(chuàng)建出來(lái),為什么Spring沒(méi)有在創(chuàng)建對(duì)象的時(shí)候進(jìn)行攔截代理呢?道理很簡(jiǎn)單,我們?cè)贗OC的文章提出了Spring在創(chuàng)建對(duì)象后還需要執(zhí)行屬性注入,生命周期等步驟,如果我們提前將對(duì)象進(jìn)行代理,我們能否對(duì)對(duì)象實(shí)施屬性注入、生命周期這都不能確定。那么Spring是在哪里進(jìn)行代理的呢?我們將代碼停在屬性注入的下面

image

發(fā)現(xiàn)并沒(méi)有被代理,我們執(zhí)行下一步

image

發(fā)現(xiàn)該對(duì)象已經(jīng)被我們的CGLIB進(jìn)行代理,那么在這段代碼里面就進(jìn)做了什么操作呢?我們跟蹤下一這段代碼:exposedObject = initializeBean(beanName, exposedObject, mbd);我們一路跟蹤停在這里

image

然后點(diǎn)擊去

image

循環(huán)我們的后置處理器獲取我們所需要的AspectJAwareAdvisorAutoProxyCreator->postProcessAfterInitialization

image

然后我們?cè)俣葘⒋a停在這里

image

看名字我們大概能猜到這里就是代理的關(guān)鍵代碼,我們跟進(jìn)下去

image

然后獲取一些adviors

image

我們其實(shí)可以猜到,這里就是獲取我們的AspectTest的信息

image

好了,既然我們獲取了我們的代理配置,那么就要開(kāi)始對(duì)我們所符合標(biāo)準(zhǔn)的代理對(duì)象進(jìn)行代理了

image

進(jìn)createProxy方法在-》 proxyFactory.getProxy(getProxyClassLoader());

image

很明顯這里就是真正創(chuàng)建代理的角色了,繼續(xù)跟蹤代碼

image

這里就是根據(jù)什么樣的需求創(chuàng)建什么樣的代理方式,注意這里僅僅只是方式,并不是真正創(chuàng)建代理對(duì)象的邏輯,比如我們這里代理的是類,那么會(huì)選擇CGLIB的方式

image

然后我們?cè)倩氐角懊娴拇a

image

可以看到createAopProxy()獲取的就是我們創(chuàng)建代理的方式,至于我們的getProxy(),筆者就不多寫了,內(nèi)部就是如何使用cglib增強(qiáng)的代碼,筆者在@Configuration中對(duì)如何通過(guò)cglib代理對(duì)象做了大量分析,這里就略過(guò),那么我們已經(jīng)知道了Spring AOP的代理流程,那么其實(shí)還缺少一樣?xùn)|西,不知讀者是否發(fā)現(xiàn)我們的adviors并不知道什么時(shí)候就存在了呢?接下來(lái)我們就去解答這個(gè)問(wèn)題,首先我們將代碼停在doCreateBean():的上面,doCreateBean()我們?cè)贗OC創(chuàng)建Bean進(jìn)行了詳細(xì)介紹,就是開(kāi)始創(chuàng)建Bean,那么對(duì)adviors的操作明顯就是在創(chuàng)建Bean之前就完成了,為了驗(yàn)證我們將代碼跟進(jìn):

image

進(jìn)入代碼

image

注意這個(gè)getBeanPostProcessors(),一共有九個(gè),這里會(huì)循環(huán)獲取

image

找到我們AOP注冊(cè)的后置處理器,然后點(diǎn)進(jìn)去

image

注意postProcessBeforeInstantiation,其實(shí)就是實(shí)例化之前的操作,Spring的命名十分規(guī)范,我們?cè)谏衔慕榻B了這是在doCreateBean之前操作的,所以稱為實(shí)例化之前,我們停留在這里

image

點(diǎn)擊去shouldSkip,繼續(xù)跟蹤跟蹤

image

然后進(jìn)入

image

然后進(jìn)入會(huì)發(fā)現(xiàn)這個(gè)buildAspectJAdvisors方法很長(zhǎng),我們直接找到關(guān)鍵代碼

image

可以看到我們就是用過(guò)this.advisorFactory.getAdvisors(factory);這句代碼獲取我們切面的方法,我們?cè)谶M(jìn)入getAdvisors(factory)


@Override
  public List<Advisor> getAdvisors(MetadataAwareAspectInstanceFactory maaif) {
    final Class<?> aspectClass = maaif.getAspectMetadata().getAspectClass();
    final String aspectName = maaif.getAspectMetadata().getAspectName();
    validate(aspectClass);

    // We need to wrap the MetadataAwareAspectInstanceFactory with a decorator
    // so that it will only instantiate once.
    final MetadataAwareAspectInstanceFactory lazySingletonAspectInstanceFactory =
        new LazySingletonAspectInstanceFactoryDecorator(maaif);

    final List<Advisor> advisors = new LinkedList<Advisor>();
    for (Method method : getAdvisorMethods(aspectClass)) {
      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;
  }

其實(shí)這里面就是通過(guò)反射的方式獲取我們的方法,返回后在存起來(lái)交給我們后面對(duì)被代理類進(jìn)行增強(qiáng),至此Spring AOP源碼分析到此為止,Spring 事物其實(shí)和我所提到Spring源碼第七章和本章思想大致一致,筆者就不在對(duì)事物進(jìn)行單獨(dú)敘述了,下一章將會(huì)更新SpringMVC。

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

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