Spring AOP源碼解讀1 - 程序入口

前言

最近看了《從零開(kāi)始寫(xiě)JavaWeb框架》,想比較一下Spring AOP的實(shí)現(xiàn)方式和書(shū)的上實(shí)現(xiàn)方式有什么不同,所以先把Spring AOP的源碼讀一下,再進(jìn)行比較。

Spring的源碼實(shí)在是復(fù)雜,在讀的過(guò)程中參考了很多書(shū)和網(wǎng)上的文章,本文算是這些文章的總結(jié),再加上一些我自己對(duì)另個(gè)細(xì)節(jié)的理解。

本文分成 3 部分:

  • 程序入口
  • 切面和增強(qiáng)的取得
  • 代理的生成

一,注冊(cè)AspectJAnnotationAutoProxyCreator

如果使用<aop:aspectj-autoproxy />標(biāo)簽來(lái)自動(dòng)生成代理的話(huà),入口程序是AopNamespaceHandler。在AopNamespaceHandler中,下面一段代碼是對(duì)<aop:aspectj-autoproxy />標(biāo)簽執(zhí)行的調(diào)用:

registerBeanDefinitionParser("aspectj-autoproxy", new AspectJAutoProxyBeanDefinitionParser());

AspectJAutoProxyBeanDefinitionParser解析器中,首先調(diào)用的parse方法。parse方法中有一行代碼:

AopNamespaceUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(parserContext, element);

我們看一下registerAspectJAnnotationAutoProxyCreatorIfNecessary方法的實(shí)際內(nèi)容:

public static void registerAutoProxyCreatorIfNecessary(
    ParserContext parserContext, Element sourceElement) {
    // 注冊(cè)或更新 AutoProxyCreator 定義 beanName 為 org.Springframework.aop.config.internalAutoProxyCreator的BeanDefinition
    // 如果internalAutoProxyCreator的BeanDefinition已經(jīng)存在,而根據(jù)優(yōu)先級(jí)更新BeanDefinition
    // 在這里我們注冊(cè)的是AnnotationAwareAspectJAutoProxyCreator
    BeanDefinition beanDefinition = AopConfigUtils.registerAutoProxyCreatorIfNecessary(
            parserContext.getRegistry(), parserContext.extractSource(sourceElement));
    // 對(duì)于 proxy-target-class 以及 expose-proxy 屬性的處理
    useClassProxyingIfNecessary(parserContext.getRegistry(), sourceElement);
    // 注冊(cè)組件并通知,便于監(jiān)聽(tīng)器作進(jìn)一步處理
    // 其中 beanDefinition 的 className 為 AnnotationAwareAspectJAutoProxyCreator
    registerComponentIfNecessary(beanDefinition, parserContext);
}



那為什么注冊(cè)AnnotationAwareAspectJAutoProxyCreator,注冊(cè)AnnotationAwareAspectJAutoProxyCreator有什么用呢?

其實(shí),實(shí)現(xiàn)AOP處理是其實(shí)是通過(guò)BeanPostProcessor機(jī)制實(shí)現(xiàn)的。AnnotationAwareAspectJAutoProxyCreator的父類(lèi)也實(shí)現(xiàn)一個(gè)BeanPostProcessor類(lèi)型的接口,而生成代理的邏輯就在AnnotationAwareAspectJAutoProxyCreator的BeanPostProcessor接口實(shí)現(xiàn)里面。
更嚴(yán)謹(jǐn)?shù)卣f(shuō),AnnotationAwareAspectJAutoProxyCreator的父類(lèi)實(shí)現(xiàn)的接口是
SmartInstantiationAwareBeanPostProcessor,主要是Spring框架內(nèi)部使用的一個(gè)接口。而這個(gè)接口的父接口InstantiationAwareBeanPostProcessor 是實(shí)現(xiàn)代理的重點(diǎn)之一。

這3個(gè)接口的關(guān)系如下:
SmartInstantiationAwareBeanPostProcessor -> InstantiationAwareBeanPostProcessor -> BeanPostProcessor

為什么說(shuō)是是InstantiationAwareBeanPostProcessor接口的子接口,接口是重點(diǎn)之一?那InstantiationAwareBeanPostProcessor接口是什么接口呢?

BeanPostProcessor主要作用于Bean實(shí)例化后,初始化前后。InstantiationAwareBeanPostProcessor雖然是BeanPostProcessor的子接口,但它的調(diào)用時(shí)間點(diǎn)其發(fā)生在Bean實(shí)例化前,在真正調(diào)用doCreate()創(chuàng)建bean實(shí)例之前。
在創(chuàng)建Bean實(shí)例之前,會(huì)先調(diào)用resolveBeforeInstantiation方法,這個(gè)方法是生成Bean代理的地方。如果此方法返回值不為空則直接返回生成的Bean的代理,如果為空就向下走正常的Bean生成流程。

spring注釋“Give BeanPostProcessors a chance to return a proxy instead of the target bean instance. ”給BeanPostProcessors一個(gè)機(jī)會(huì)返回代理proxy對(duì)象。

InstantiationAwareBeanPostProcessor接口方法,就是在resolveBeforeInstantiation方法中調(diào)用的。所以可以看出,BeanPostProcessore有很多,但Spring AOP的實(shí)現(xiàn)就是通過(guò)InstantiationAwareBeanPostProcessor這個(gè)BeanPostProcessor實(shí)現(xiàn)的??匆幌略创a:

protected Object createBean(final String beanName, final RootBeanDefinition mbd, final Object[] args)
        throws BeanCreationException {
    ......
    try {
        // Give BeanPostProcessors a chance to return a proxy instead of the target bean instance.
        // 如果返回值不為空,說(shuō)明生成成了此BeanName的代理,直接返回代理對(duì)象
        Object bean = resolveBeforeInstantiation(beanName, mbd);
        if (bean != null) {
            return bean;
        }
    }
    catch (Throwable ex) {
        ......
    }

    // 如果沒(méi)有生成代理對(duì)象,就按正常流程走,生成Bean對(duì)象
    Object beanInstance = doCreateBean(beanName, mbd, args);
    .....
    return beanInstance;
}
protected Object resolveBeforeInstantiation(String beanName, RootBeanDefinition mbd) {
    Object bean = null;
    if (!Boolean.FALSE.equals(mbd.beforeInstantiationResolved)) {
        // Make sure bean class is actually resolved at this point.
        if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
            Class<?> targetType = determineTargetType(beanName, mbd);
            if (targetType != null) {
                // 調(diào)用InstantiationAwareBeanPostProcessor接口的地方
                bean = applyBeanPostProcessorsBeforeInstantiation(targetType, beanName);
                if (bean != null) {
                    bean = applyBeanPostProcessorsAfterInitialization(bean, beanName);
                }
            }
        }
        mbd.beforeInstantiationResolved = (bean != null);
    }
    return bean;
}
    protected Object applyBeanPostProcessorsBeforeInstantiation(Class<?> beanClass, String beanName)
            throws BeansException {

        for (BeanPostProcessor bp : getBeanPostProcessors()) {
            if (bp instanceof InstantiationAwareBeanPostProcessor) {
                // 轉(zhuǎn)換成InstantiationAwareBeanPostProcessor接口,并調(diào)用
                InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
                Object result = ibp.postProcessBeforeInstantiation(beanClass, beanName);
                if (result != null) {
                    return result;
                }
            }
        }
        return null;
    }

順帶說(shuō)一下,注冊(cè)AnnotationAwareAspectJAutoProxyCreator的目的是:把這個(gè)類(lèi)的BeanDefinition通過(guò)registerBeanDefinition方法(DefaultListableBeanFactory類(lèi)中)加入到beanDefinitionMap中,作為一個(gè)Bean讓Spring管理,這樣Spring就可以隨意取得它了。



如果使用<aop:aspectj-autoproxy />標(biāo)簽來(lái)自動(dòng)生成代理的話(huà),入口程序是AopNamespaceHandler。那AopNamespaceHandler 是在什么地方被調(diào)用的呢?
這個(gè)問(wèn)題讓我們從容器啟動(dòng)的地方開(kāi)始說(shuō)明。以FileSystemXmlApplicationContext 為例,這個(gè)類(lèi)的入口是構(gòu)造函數(shù)里面的refresh() 方法。從refresh() 方法開(kāi)始,調(diào)用流程是這樣的:(以下流程全部是嵌套調(diào)用的關(guān)系)

1. refresh() ->
   刷新容器 
2. obtainFreshBeanFactory() ->
   獲得刷新后的Bean容器
3. refreshBeanFactory() ->
   刷新Bean容器
4. loadBeanDefinitions() ->
   加載BeanDefinition
5. XmlBeanDefinitionReader#loadBeanDefinitions
   新建一個(gè)XmlBeanDefinitionReader實(shí)例(new XmlBeanDefinitionReader(beanFactory)),調(diào)用這個(gè)實(shí)例的loadBeanDefinitions方法。
6. XmlBeanDefinitionReader#doLoadBeanDefinitions
7. XmlBeanDefinitionReader#registerBeanDefinitions
8. XmlBeanDefinitionReader#createBeanDefinitionDocumentReader
   在這個(gè)方法中取得了DefaultBeanDefinitionDocumentReader實(shí)例。接下來(lái)調(diào)用這個(gè)實(shí)例的方法。
9. DefaultBeanDefinitionDocumentReader#registerBeanDefinitions
   在這個(gè)方法中,根據(jù)URI判斷是否使用AopNamespaceHandler
10. DefaultBeanDefinitionDocumentReader#parseBeanDefinitions
   從registerBeanDefinitions方法開(kāi)始,內(nèi)部連續(xù)調(diào)用一系列方法,一直調(diào)用到parseBeanDefinitions方法。在這個(gè)方法中,根據(jù)XML文件的URI判斷使用哪些解析器,例如是<Beans>類(lèi)標(biāo)簽解析器,還是<aop>類(lèi)標(biāo)簽解析器。
   如果是需要<aop>標(biāo)簽解析器的話(huà),在this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri)代碼中,從配置文件(spring.handlers)從取出AopNamespaceHandler的類(lèi)名,生成這個(gè)類(lèi)的實(shí)例,然后調(diào)用這個(gè)類(lèi)的parse方法。
11. AopNamespaceHandler#parse
   這個(gè)方法的功能是,根據(jù)具體標(biāo)簽調(diào)用具體解析器的parse方法。
   - <aop:aspectj-autoproxy>:AspectJAutoProxyBeanDefinitionParser
   - <aop:config>:ConfigBeanDefinitionParser
   等。
   這個(gè)方法的調(diào)用,又回到了我們最初講的AopNamespaceHandler入口的地方。

到此為止,從容器到AopNamespaceHandler類(lèi)調(diào)用的過(guò)程也講完了。
            

二,AspectJAnnotationAutoProxyCreator的流程

通過(guò)上面的內(nèi)容,我們知道了注冊(cè)AnnotationAwareAspectJAutoProxyCreator的意義,并且知道了生成代理是在它的BeanPostProcessor接口里做的,現(xiàn)在看看被實(shí)現(xiàn)的接口的內(nèi)容。(postProcessAfterInitialization 具體實(shí)現(xiàn)是在其父類(lèi) AbstractAutoProxyCreator 中完成的):

@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
   if (bean != null) {
      // 根據(jù)給定的 bean 的 class 和 name 構(gòu)建出個(gè) key,格式:beanClassName_beanName
      Object cacheKey = getCacheKey(bean.getClass(), beanName);
      if (!this.earlyProxyReferences.contains(cacheKey)) {
         // 如果它適合被代理,則需要封裝指定 bean。
         return wrapIfNecessary(bean, beanName, cacheKey);
      }
   }
   return bean;
}
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
   // 是否已經(jīng)處理過(guò)
   if (beanName != null && this.targetSourcedBeans.contains(beanName)) {
      return bean;
   }
   // 無(wú)需增強(qiáng)
   if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
      return bean;
   }
   // 給定的 bean 類(lèi)是否代表一個(gè)基礎(chǔ)設(shè)施類(lèi),基礎(chǔ)設(shè)施類(lèi)不應(yīng)代理,或者配置了指定 bean 不需要自動(dòng)代理
   if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
      this.advisedBeans.put(cacheKey, Boolean.FALSE);
      return bean;
   }

   // 如果存在增強(qiáng)方法則創(chuàng)建代理(*重要*)
   Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
   // 如果獲取到了增強(qiáng)則需要針對(duì)增強(qiáng)創(chuàng)建代理
   if (specificInterceptors != DO_NOT_PROXY) {
      this.advisedBeans.put(cacheKey, Boolean.TRUE);
      // 創(chuàng)建代理(*重要*)
      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;
}

這里有兩個(gè)方法特別重要:

  1. getAdvicesAndAdvisorsForBean:如果Bean是要被代理的對(duì)象的話(huà),取得Bean相關(guān)的Interceptor
  2. createProxy:創(chuàng)建代理

下一篇文章,我們就這兩個(gè)方法的下面的流程分開(kāi)來(lái)分析一下,首先分析getAdvicesAndAdvisorsForBean相關(guān)代碼。




關(guān)于接口實(shí)現(xiàn)的補(bǔ)充:

AnnotationAwareAspectJAutoProxyCreator 一共實(shí)現(xiàn)了2個(gè)BeanPostProcessor 的接口,的4個(gè)方法:

  • postProcessBeforeInstantiation(InstantiationAwareBeanPostProcessor)
  • postProcessAfterInstantiation(InstantiationAwareBeanPostProcessor)
  • postProcessBeforeInitialization(BeanPostProcessor)
  • postProcessAfterInitialization(BeanPostProcessor)

postProcessBeforeInstantiationInstantiationAwareBeanPostProcessor接口)方法中,這個(gè)方法是在AnnotationAwareAspectJAutoProxyCreator的基類(lèi)AbstractAutoProxyCreator中實(shí)現(xiàn)的。細(xì)看一下,在postProcessAfterInitialization方法中也有類(lèi)似的生成代理的代碼。這是為什么呢?

上網(wǎng)找了一些資料,在postProcessBeforeInstantiation方法中有一個(gè)判斷:

如果某個(gè)Bean設(shè)置了自定義TargetSource的話(huà),就在本方法中進(jìn)行生成代理

postProcessAfterInitialization則沒(méi)有這樣的判斷,只是在生成代理前判斷了一下代理是否已經(jīng)生成。具體為什么有這樣的必須還不清楚(以后有需要調(diào)查一下),但結(jié)果就是:

  • 如果Bean設(shè)置了自定義TargetSource,就在postProcessBeforeInstantiation中生成代理
  • 如果沒(méi)有,就在postProcessAfterInitialization中生成代理。

最后,不管理在哪個(gè)方法里生成代理,在創(chuàng)建每個(gè)Bean時(shí)都會(huì)被調(diào)用這兩個(gè)方法,代理的生成邏輯就是在這兩個(gè)方法中實(shí)現(xiàn)的。

關(guān)于TargetSource:spring-aop組件詳解——TargetSource目標(biāo)源
關(guān)于自定義TargetSource:《Spring揭密》的9.6章節(jié)

最后編輯于
?著作權(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)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

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

  • Spring Cloud為開(kāi)發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見(jiàn)模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 136,554評(píng)論 19 139
  • 什么是Spring Spring是一個(gè)開(kāi)源的Java EE開(kāi)發(fā)框架。Spring框架的核心功能可以應(yīng)用在任何Jav...
    jemmm閱讀 16,771評(píng)論 1 133
  • Spring Boot 參考指南 介紹 轉(zhuǎn)載自:https://www.gitbook.com/book/qbgb...
    毛宇鵬閱讀 47,273評(píng)論 6 342
  • Spring簡(jiǎn)介 spring框架由Rod Johnson開(kāi)發(fā),2004年發(fā)布了Spring框架的第一版。Spri...
    qiuqiu_hz閱讀 1,112評(píng)論 0 15
  • 1.項(xiàng)目基本算是完成了 但遺留了兩個(gè)bug 明天解決 做項(xiàng)目時(shí)"小"錯(cuò)誤? a.接口文檔未細(xì)致看 b.單詞錯(cuò)誤 c...
    小小太陽(yáng)000閱讀 269評(píng)論 0 0

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