曹工說Spring Boot源碼(17)-- Spring從xml文件裏到底獲得了什麼(aop:config完整解析【中】)

寫在前面的話

相關背景及資源:html

曹工說Spring Boot源碼(1)-- Bean Definition究竟是什麼,附spring思惟導圖分享java

曹工說Spring Boot源碼(2)-- Bean Definition究竟是什麼,我們對着接口,逐個方法講解node

曹工說Spring Boot源碼(3)-- 手動註冊Bean Definition不比遊戲好玩嗎,咱們來試一下git

曹工說Spring Boot源碼(4)-- 我是怎麼自定義ApplicationContext,從json文件讀取bean definition的?spring

曹工說Spring Boot源碼(5)-- 怎麼從properties文件讀取beanexpress

曹工說Spring Boot源碼(6)-- Spring怎麼從xml文件裏解析bean的json

曹工說Spring Boot源碼(7)-- Spring解析xml文件,到底從中獲得了什麼(上)框架

曹工說Spring Boot源碼(8)-- Spring解析xml文件,到底從中獲得了什麼(util命名空間)ide

曹工說Spring Boot源碼(9)-- Spring解析xml文件,到底從中獲得了什麼(context命名空間上)函數

曹工說Spring Boot源碼(10)-- Spring解析xml文件,到底從中獲得了什麼(context:annotation-config 解析)

曹工說Spring Boot源碼(11)-- context:component-scan,你真的會用嗎(此次來講說它的奇技淫巧)

曹工說Spring Boot源碼(12)-- Spring解析xml文件,到底從中獲得了什麼(context:component-scan完整解析)

曹工說Spring Boot源碼(13)-- AspectJ的運行時織入(Load-Time-Weaving),基本內容是講清楚了(附源碼)

曹工說Spring Boot源碼(14)-- AspectJ的Load-Time-Weaving的兩種實現方式細細講解,以及怎麼和Spring Instrumentation集成

曹工說Spring Boot源碼(15)-- Spring從xml文件裏到底獲得了什麼(context:load-time-weaver 完整解析)

曹工說Spring Boot源碼(16)-- Spring從xml文件裏到底獲得了什麼(aop:config完整解析【上】)

工程代碼地址 思惟導圖地址

工程結構圖:

概要

本篇是接着上一篇講的,爲了不沒必要要的重複,請你們先看下前一篇。

曹工說Spring Boot源碼(16)-- Spring從xml文件裏到底獲得了什麼(aop:config完整解析【上】)

本篇主要講一個主題,解析xml後,獲取到了哪些bean definition。

解析xml,獲取業務相關的切點、切面等bean definition

爲了講述方便,這裏貼一下spring要解析的xml:

<!--目標對象-->
<bean id="performer" class="foo.Performer"/>

<!--切面-->
<bean id="performAspect" class="foo.PerformAspect"/>

<!--配置切入點-->
<aop:config>
    <aop:pointcut id="mypointcut" expression="execution(public * foo.Perform.sing(..))"/>
    <aop:aspect id="myAspect" ref="performAspect">
        <aop:after method="afterPerform" pointcut-ref="mypointcut"/>
    </aop:aspect>
</aop:config>

前面兩個業務bean,沒啥說的,一個是target對象,一個是切面對象。核心的解析主要是 ,在spring裏,解析該元素的代碼在:

public class AopNamespaceHandler extends NamespaceHandlerSupport {

   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   這個已經移到context命名空間了
      registerBeanDefinitionParser("spring-configured", new SpringConfiguredBeanDefinitionParser());
   }

}

aop命名空間裏,一共4個元素,其中一個"spring-configured"移到了context命名空間了,因此剩三個。這三個元素,對應的解析類,在上面的init方法中一目瞭然。其中,aop:config對應的解析類,爲ConfigBeanDefinitionParser。

在下面的parse方法中,參數element即爲當前解析到的 ,首先,建立了一個用於代理建立的bean definition;而後獲取本元素的子元素,子元素多是 aop:pointcut,aop:aspect,aop:advisor,而後對其進行相應的處理。

public BeanDefinition parse(Element element, ParserContext parserContext) {
   // 配置代理建立bean definition,是一個beanPostProcessor類型的bean definition
   configureAutoProxyCreator(parserContext, element);

   // 獲取aop元素下的子元素
   List<Element> childElts = DomUtils.getChildElements(element);
   for (Element elt: childElts) {
      String localName = parserContext.getDelegate().getLocalName(elt);
      // 若是元素名等於pointcut,則走下面
      if (POINTCUT.equals(localName)) {
         parsePointcut(elt, parserContext);
      }
      // 若是元素名等於 advisor,則走下面
      else if (ADVISOR.equals(localName)) {
         parseAdvisor(elt, parserContext);
      }
      // 若是元素名等於 aspect,則走下面
      else if (ASPECT.equals(localName)) {
         parseAspect(elt, parserContext);
      }
   }

   return null;
}

爲了講解清晰,咱們先講解幾個子元素的解析過程。

aop:pointcut解析

#org.springframework.aop.config.ConfigBeanDefinitionParser#parsePointcut
private AbstractBeanDefinition parsePointcut(Element pointcutElement, ParserContext parserContext) {
   //獲取id和expression屬性
   String id = pointcutElement.getAttribute(ID);
   String expression = pointcutElement.getAttribute(EXPRESSION);
   
   // 1. 根據expression,建立bean definition
   AbstractBeanDefinition pointcutDefinition = createPointcutDefinition(expression);;
   
   // 2. 向ioc容器,註冊bean definition,註冊的操做是由下面的registerBeanDefinition調用完成
   String pointcutBeanName = id;
   if (StringUtils.hasText(pointcutBeanName)) {
        parserContext.getRegistry().registerBeanDefinition(pointcutBeanName, pointcutDefinition);
   }
   else {
        pointcutBeanName = parserContext.getReaderContext().registerWithGeneratedName(pointcutDefinition);
   }


   return pointcutDefinition;
}

上面的代碼,主要有2個步驟,生成bean definition和向BeanDefinitionRegistry(通常beanFactory實現了該接口)註冊該bean definition。

生成beanDefinition的代碼,主要在如下方法:

protected AbstractBeanDefinition createPointcutDefinition(String expression) {
   RootBeanDefinition beanDefinition = new RootBeanDefinition(AspectJExpressionPointcut.class);
   beanDefinition.setScope(BeanDefinition.SCOPE_PROTOTYPE);
   beanDefinition.setSynthetic(true);
   beanDefinition.getPropertyValues().add(EXPRESSION, expression);
   return beanDefinition;
}

你們能夠看到,這裏new了一個RootBeanDefinition,這是一個BeanDefinition接口的實現,框架內部的bean的beandefinition,通常都是這個類型。這裏能夠看到,這個bean definition的class類型爲AspectJExpressionPointcut,scope爲prototype,並且經過如下代碼,設置了一個屬性值。

beanDefinition.getPropertyValues().add(EXPRESSION, expression);

propertValues這個屬性,你們能夠理解爲xml時代,像下面這樣配置屬性:

<bean class="foo.TestPropertiesVO">
    <property name="name" value="abc"/>
</bean>

其實也不能說是「像」,由於spring解析上面這個xml,就會使用beanDefinition.getPropertyValues().add(EXPRESSION, expression)這樣的代碼來解析。

ok,切點解析,咱們就是獲得了一個AspectJExpressionPointcut類型的bean definition。

aop:aspect解析

# org.springframework.aop.config.ConfigBeanDefinitionParser#parseAspect 
# 去掉了部分無關代碼
private void parseAspect(Element aspectElement, ParserContext parserContext) {
   String aspectId = aspectElement.getAttribute(ID);
   String aspectName = aspectElement.getAttribute(REF);
    
    List<BeanDefinition> beanDefinitions = new ArrayList<BeanDefinition>();
    List<BeanReference> beanReferences = new ArrayList<BeanReference>();

    NodeList nodeList = aspectElement.getChildNodes();
    boolean adviceFoundAlready = false;
    //遍歷子元素
    for (int i = 0; i < nodeList.getLength(); i++) {
        Node node = nodeList.item(i);
        if (isAdviceNode(node, parserContext)) {
            if (!adviceFoundAlready) {
                adviceFoundAlready = true;
                // 這裏實際上是要把<aop:aspect ref="performAspect"> 這一句裏面的ref引用的切面存起來
                beanReferences.add(new RuntimeBeanReference(aspectName));
            }
            // 解析每個子元素,獲取一個bean definition。這裏的子元素就是<aop:before> <aop:after>等
            AbstractBeanDefinition advisorDefinition = parseAdvice(
                aspectName, i, aspectElement, (Element) node, parserContext, beanDefinitions, beanReferences);
            beanDefinitions.add(advisorDefinition);
        }
    }
}

上面這段代碼,有3點要說明的。

  1. 這裏經過String aspectName = aspectElement.getAttribute(REF);獲取了通知bean的bean name,也就是<aop:aspect ref="performAspect">這裏面的那個performAspect。這個東西,後面會用;

  2. aspectElement.getChildNodes();獲取了子元素,當前是<aop:aspect ref="performAspect">,那麼子元素就是<aop:before><aop:after>這些。每次遍歷,都會生成一個AbstractBeanDefinition advisorDefinition,也就是說,每次遍歷都會生成一個bean definition。

  3. 具體的<aop:after>代碼以下:

    private AbstractBeanDefinition parseAdvice(
          String aspectName, int order, Element aspectElement, Element adviceElement, ParserContext parserContext,
          List<BeanDefinition> beanDefinitions, List<BeanReference> beanReferences) {
    
    
          // 1.建立bean definition,類型爲 MethodLocatingFactoryBean;會交給第三步使用
          RootBeanDefinition methodDefinition = new RootBeanDefinition(MethodLocatingFactoryBean.class);
          methodDefinition.getPropertyValues().add("targetBeanName", aspectName);
          methodDefinition.getPropertyValues().add("methodName", adviceElement.getAttribute("method"));
          methodDefinition.setSynthetic(true);
    
          // 2.建立bean definition,類型爲SimpleBeanFactoryAwareAspectInstanceFactory;會交給第三步使用
          RootBeanDefinition aspectFactoryDef =
                new RootBeanDefinition(SimpleBeanFactoryAwareAspectInstanceFactory.class);
          aspectFactoryDef.getPropertyValues().add("aspectBeanName", aspectName);
          aspectFactoryDef.setSynthetic(true);
    
          // 3.建立aop:after對應的類型的bean definition;若是是aop:before,這裏的類型不同
          AbstractBeanDefinition adviceDef = createAdviceDefinition(
                adviceElement, parserContext, aspectName, order, methodDefinition, aspectFactoryDef,
                beanDefinitions, beanReferences);
    
          // 4. 建立bean definition,類型爲 AspectJPointcutAdvisor
          RootBeanDefinition advisorDefinition = new RootBeanDefinition(AspectJPointcutAdvisor.class);
          advisorDefinition.setSource(parserContext.extractSource(adviceElement));
          advisorDefinition.getConstructorArgumentValues().addGenericArgumentValue(adviceDef);
          if (aspectElement.hasAttribute(ORDER_PROPERTY)) {
             advisorDefinition.getPropertyValues().add(
                   ORDER_PROPERTY, aspectElement.getAttribute(ORDER_PROPERTY));
          }
    
          // 5. 註冊第四步建立的AspectJPointcutAdvisor類型的bean definition
          parserContext.getReaderContext().registerWithGeneratedName(advisorDefinition);
    
          return advisorDefinition;
    }

    有人看到上面一坨,不要慌,其實不難。第一步和第二步,建立了2個bean definition,都是給第三步服務的。第三步,我這裏給你們說,根據不一樣的子元素,bean definition的class是不同的,你們直接看如下代碼:

    org.springframework.aop.config.ConfigBeanDefinitionParser#getAdviceClass
    private Class getAdviceClass(Element adviceElement, ParserContext parserContext) {
       String elementName = parserContext.getDelegate().getLocalName(adviceElement);
       if (BEFORE.equals(elementName)) {
          return AspectJMethodBeforeAdvice.class;
       }
       else if (AFTER.equals(elementName)) {
          return AspectJAfterAdvice.class;
       }
       else if (AFTER_RETURNING_ELEMENT.equals(elementName)) {
          return AspectJAfterReturningAdvice.class;
       }
       else if (AFTER_THROWING_ELEMENT.equals(elementName)) {
          return AspectJAfterThrowingAdvice.class;
       }
       else if (AROUND.equals(elementName)) {
          return AspectJAroundAdvice.class;
       }
       else {
          throw new IllegalArgumentException("Unknown advice kind [" + elementName + "].");
       }
    }

    由於咱們這裏是aop:after,因此咱們這裏的bean 類型爲AspectJAfterAdvice。

    咱們進一步,看看AspectJAfterAdvice這個類的代碼:

    public class AspectJAfterAdvice extends AbstractAspectJAdvice implements MethodInterceptor, AfterAdvice {
    
       public AspectJAfterAdvice(
             Method aspectJBeforeAdviceMethod, AspectJExpressionPointcut pointcut, AspectInstanceFactory aif) {
    
          super(aspectJBeforeAdviceMethod, pointcut, aif);
       }
       ...
    }

    能夠看到,這個class,只有一個構造函數,須要三個參數。咱們仔細看看,其實前面的第一步和第二步,建立的bean definition,就是給這個構造函數服務的。

    AspectJAfterAdvice構造函數參數 解析代碼中建立的bean definition
    Method aspectJBeforeAdviceMethod 步驟1,類型爲MethodLocatingFactoryBean。其實現了接口FactoryBean<Method>,經過ioc容器,獲取factorybean,直接就能獲取到其生產的對象,這裏這個工廠,生產的對象,就是Method類型的
    AspectJExpressionPointcut pointcut 步驟3,todo
    AspectInstanceFactory aif 步驟2,類型爲SimpleBeanFactoryAwareAspectInstanceFactory,其實現了AspectInstanceFactory接口

    你們看了這個表格,應該清楚了很多,其中第二個參數還沒講到,咱們跳轉到步驟3的具體實現中:

    private AbstractBeanDefinition createAdviceDefinition(
          Element adviceElement, ParserContext parserContext, String aspectName, int order,
          RootBeanDefinition methodDef, RootBeanDefinition aspectFactoryDef,
          List<BeanDefinition> beanDefinitions, List<BeanReference> beanReferences) {
       // 這裏的getAdviceClass,就是根據元素類型,獲取不一樣的bean class類型
       RootBeanDefinition adviceDefinition = new RootBeanDefinition(getAdviceClass(adviceElement, parserContext));
       // 設置aspectName屬性,來源於<aop:aspect ref="performAspect">
       adviceDefinition.getPropertyValues().add(ASPECT_NAME_PROPERTY, aspectName);
       // 設置本 bean definition的類的構造參數,咱們這裏,即AspectJAfterAdvice的構造函數參數
       ConstructorArgumentValues cav = adviceDefinition.getConstructorArgumentValues();
       cav.addIndexedArgumentValue(0, methodDef);
    
       Object pointcut = parsePointcutProperty(adviceElement, parserContext);
       RuntimeBeanReference pointcutRef = new RuntimeBeanReference((String) pointcut);
       cav.addIndexedArgumentValue(1, pointcutRef);
       beanReferences.add(pointcutRef);
    
    
       cav.addIndexedArgumentValue(2, aspectFactoryDef);
    
       return adviceDefinition;
    }

    我想了下,拿圖說話吧:

    這個AspectJAfterAdvice的bean definition中的構造函數參數這塊,就接收上面圖裏的3個參數,其中參數1和3,都是RootBeanDefinition;參數2,爲針對bean的引用。

前面講了,怎麼去構造AspectJAfterAdvice這種bean definition了,但還有一段沒講:

// 4. 建立bean definition,類型爲 AspectJPointcutAdvisor
      RootBeanDefinition advisorDefinition = new RootBeanDefinition(AspectJPointcutAdvisor.class);
      advisorDefinition.setSource(parserContext.extractSource(adviceElement));
      advisorDefinition.getConstructorArgumentValues().addGenericArgumentValue(adviceDef);
      if (aspectElement.hasAttribute(ORDER_PROPERTY)) {
         advisorDefinition.getPropertyValues().add(
               ORDER_PROPERTY, aspectElement.getAttribute(ORDER_PROPERTY));
      }

      // 5. 註冊第四步建立的AspectJPointcutAdvisor類型的bean definition
      parserContext.getReaderContext().registerWithGeneratedName(advisorDefinition);

      return advisorDefinition;
}

這裏其實就是利用前面拿到的AspectJAfterAdvice,去構造這裏第四步的AspectJPointcutAdvisor類型的bean definition。你們直接看看以下代碼:

public AspectJPointcutAdvisor(AbstractAspectJAdvice advice) {
    Assert.notNull(advice, "Advice must not be null");
    this.advice = advice;
    this.pointcut = advice.buildSafePointcut();
}

因此,就是說,第四步的bean definition,在構造這個bean的時候,由於沒有無參構造函數,而只有這個帶一個AbstractAspectJAdvice類型參數的構造函數。

具體的,你們看下面的圖,更容易理解。

而後,這個最外層的AspectJPointcutAdvisor的bean definition,被註冊到ioc容器;而值得一提的是,其餘的幾個bean definition,並無被註冊到ioc容器。

彙總一下,目前爲止,解析下面這段xml,咱們的收穫以下:

<aop:config>
        <aop:pointcut id="pointcut" expression="execution(public * foo.Perform.sing(..))"/>
        <aop:aspect ref="performAspect">
            <aop:before method="beforePerform" pointcut-ref="pointcut"/>
            <aop:after method="afterPerform" pointcut-ref="pointcut"/>
        </aop:aspect>
    </aop:config>

收穫:

  1. 切點對應的bean definition,1個

    {
        "abstract": false,
        "autowireCandidate": true,
        "autowireMode": 0,
        "beanClass": "org.springframework.aop.aspectj.AspectJExpressionPointcut",
        "beanClassName": "org.springframework.aop.aspectj.AspectJExpressionPointcut",
        "constructorArgumentValues": {
          "argumentCount": 0,
          "empty": true,
          "genericArgumentValues": [],
          "indexedArgumentValues": {}
        },
        "dependencyCheck": 0,
        "enforceDestroyMethod": true,
        "enforceInitMethod": true,
        "lazyInit": false,
        "primary": false,
        "propertyValues": {
          "converted": false,
          "empty": false,
          "propertyValueList": [
            {
              "converted": false,
              "name": "expression",
              "optional": false,
              "value": "execution(public * foo.Perform.sing(..))"
            }
          ]
        },
        "prototype": true,
        "qualifiers": [],
        "resolvedAutowireMode": 0,
        "role": 0,
        "scope": "prototype",
        "singleton": false,
        "synthetic": true,
        "targetType": "org.springframework.aop.aspectj.AspectJExpressionPointcut"
      }
  2. 對應的bean definition,1個,類型爲:AspectJPointcutAdvisor

    其內部的構造函數參數,持有了一個內部的,類型爲AspectJAfterAdvice的bean definition,這個實際上是一個內部bean definition了。而這個內部bean definition的構造函數中,還持有了3個其餘的參數,2個bean definition,1個爲bean 引用。你們能夠看下面的json,比較長,我已經刪了一些無關屬性了。

    {
      "abstract": false,
      "autowireCandidate": true,
      "autowireMode": 0,
      "beanClass": "org.springframework.aop.aspectj.AspectJPointcutAdvisor",
      "beanClassName": "org.springframework.aop.aspectj.AspectJPointcutAdvisor",
      "constructorArgumentValues": {
        "argumentCount": 1,
        "empty": false,
        "genericArgumentValues": [
          {
            "converted": false,
            "value": {
              "abstract": false,
              "autowireCandidate": true,
              "autowireMode": 0,
               // 看這裏
              "beanClass": "org.springframework.aop.aspectj.AspectJAfterAdvice",
              "beanClassName": "org.springframework.aop.aspectj.AspectJAfterAdvice",
              "constructorArgumentValues": {
                "argumentCount": 3,
                "empty": false,
                "genericArgumentValues": [],
                 // 再看這裏,3個構造函數參數
                "indexedArgumentValues": {
                  "0": {
                    "converted": false,
                    "value": {
                      "abstract": false,
                      "autowireCandidate": true,
                      "autowireMode": 0,
                      "beanClass": "org.springframework.aop.config.MethodLocatingFactoryBean",
                      "beanClassName": "org.springframework.aop.config.MethodLocatingFactoryBean",
                      "constructorArgumentValues": {
                        "argumentCount": 0,
                        "empty": true,
                        "genericArgumentValues": [],
                        "indexedArgumentValues": {}
                      },
                      "nonPublicAccessAllowed": true,
                      "primary": false,
                      "propertyValues": {
                        "converted": false,
                        "empty": false,
                        "propertyValueList": [
                          {
                            "converted": false,
                            "name": "targetBeanName",
                            "optional": false,
                            "value": "performAspect"
                          },
                          {
                            "converted": false,
                            "name": "methodName",
                            "optional": false,
                            "value": "afterPerform"
                          }
                        ]
                      },
                      "prototype": false,
                      "qualifiers": [],
                      "resolvedAutowireMode": 0,
                      "role": 0,
                      "scope": "",
                      "singleton": true,
                      "synthetic": true
                    }
                  },
                  "1": {
                    "converted": false,
                    "value": {
                      "beanName": "mypointcut",
                      "toParent": false
                    }
                  },
                  "2": {
                    "converted": false,
                    "value": {
                      "abstract": false,
                      "autowireCandidate": true,
                      "autowireMode": 0,
                      "beanClass": "org.springframework.aop.config.SimpleBeanFactoryAwareAspectInstanceFactory",
                      "beanClassName": "org.springframework.aop.config.SimpleBeanFactoryAwareAspectInstanceFactory",
                      "constructorArgumentValues": {
                        "argumentCount": 0,
                        "empty": true,
                        "genericArgumentValues": [],
                        "indexedArgumentValues": {}
                      },
                      "dependencyCheck": 0,
                      "enforceDestroyMethod": true,
                      "enforceInitMethod": true,
                      "lazyInit": false,
                      "lenientConstructorResolution": true,
                      "methodOverrides": {
                        "empty": true,
                        "overrides": []
                      },
                      "nonPublicAccessAllowed": true,
                      "primary": false,
                      "propertyValues": {
                        "converted": false,
                        "empty": false,
                        "propertyValueList": [
                          {
                            "converted": false,
                            "name": "aspectBeanName",
                            "optional": false,
                            "value": "performAspect"
                          }
                        ]
                      },
                    }
                  }
                }
              },
              "nonPublicAccessAllowed": true,
              "propertyValues": {
                "converted": false,
                "empty": false,
                "propertyValueList": [
                  {
                    "converted": false,
                    "name": "aspectName",
                    "optional": false,
                    "value": "performAspect"
                  },
                  {
                    "converted": false,
                    "name": "declarationOrder",
                    "optional": false,
                    "value": 1
                  }
                ]
              },
              "prototype": false,
              "singleton": true,
              "synthetic": false
            }
          }
        ],
        "indexedArgumentValues": {}
      },
      "lazyInit": false,
      "primary": false,
      "propertyValues": {
        "converted": false,
        "empty": true,
        "propertyValueList": []
      },
      "targetType": "org.springframework.aop.aspectj.AspectJPointcutAdvisor"
    }

因此,到目前爲止,咱們收穫了2個最外層的,註冊到了ioc容器的bean definition,是能夠直接getBean的那種。

至於其他的那幾個構造函數相關的bean definition,其實都是在ioc容器裏不存在的,若是去getBean,會失敗。

好比,咱們改造了main方法以下:

public static void main(String[] args) {
    ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext(
            "context-namespace-test-aop.xml");
    // 這裏去獲取前面那個AspectJAfterAdvice bean definition
    AspectJAfterAdvice bean = ctx.getBean(AspectJAfterAdvice.class);

    Perform performer = (Perform) ctx.getBean(Perform.class);
    performer.sing();
}

結果,報錯了,NoSuchBeanDefinitionException:

Exception in thread "main" org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [org.springframework.aop.aspectj.AspectJAfterAdvice] is defined
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBean(DefaultListableBeanFactory.java:296)
    at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1196)
    at foo.Main.main(Main.java:21)

換成下面這個,也同樣:

ctx.getBean(SimpleBeanFactoryAwareAspectInstanceFactory.class);
Exception in thread "main" org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [org.springframework.aop.config.SimpleBeanFactoryAwareAspectInstanceFactory] is defined
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBean(DefaultListableBeanFactory.java:296)
    at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1196)
    at foo.Main.main(Main.java:22)

通過這麼一實驗,想必你們也能必定程度,理解內部bean了。

解析xml,獲取框架支撐型bean definition

前面一段解析,雖然費時費力,可是還沒完成所有的解析工做,拿到的都是些業務bean definition,好比在什麼地方切,切面邏輯在哪,等等,可是,這個切面要怎麼生效,還沒搞清楚。你們能夠往前翻,翻到開頭的解析處,能夠看到下面這段:

public BeanDefinition parse(Element element, ParserContext parserContext) {
        CompositeComponentDefinition compositeDef =
                new CompositeComponentDefinition(element.getTagName(), parserContext.extractSource(element));
        parserContext.pushContainingComponent(compositeDef);
        // 配置代理建立bean definition,是一個beanPostProcessor類型的bean definition
        configureAutoProxyCreator(parserContext, element);
        
        ...
    }

其中,configureAutoProxyCreator這句,就是畫龍點睛的最後一筆。其通過簡單的跳轉後,會調用:

public static BeanDefinition registerAspectJAutoProxyCreatorIfNecessary(BeanDefinitionRegistry registry, Object source) {
   return registerOrEscalateApcAsRequired(AspectJAwareAdvisorAutoProxyCreator.class, registry, source);
}

這一句,會註冊一個bean class類型爲AspectJAwareAdvisorAutoProxyCreator的bean definition,到ioc容器。

這個AspectJAwareAdvisorAutoProxyCreator類比較特別,

上圖可知,其實現了 BeanPostProcessor接口,能夠在bean的初始化先後進行一些處理,好比什麼處理呢?好比狸貓換太子,將真正的bean換成動態代理後的bean。

總結

寫到這裏,感受內容已經有點過於長了,也不方便你們理解吸取。具體的,這個AspectJAwareAdvisorAutoProxyCreator,做爲BeanPostProcessor,如何去建立代理,咱們放到下一節好好說。

同時,也會看看,在獲取AspectJPointcutAdvisor這個bean的時候,有什麼特別之處。

相關文章
相關標籤/搜索