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


寫在前面的話

相關背景及資源:

曹工說Spring Boot源碼(1)-- Bean Definition到底是什么,附spring思維導圖分享

曹工說Spring Boot源碼(2)-- Bean Definition到底是什么,咱們對着接口,逐個方法講解

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

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

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

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

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

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

曹工說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對象,一個是切面對象。核心的解析主要是aop:config,在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即為當前解析到的aop:config,首先,創建了一個用於代理創建的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. aop:aspect 對應的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的時候,有什么特別之處。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM