寫在前面的話
相關背景及資源:
曹工說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點要說明的。
-
這里通過
String aspectName = aspectElement.getAttribute(REF);
獲取了通知bean的bean name,也就是<aop:aspect ref="performAspect">
這里面的那個performAspect。這個東西,后面會用; -
aspectElement.getChildNodes();
獲取了子元素,當前是<aop:aspect ref="performAspect">
,那么子元素就是<aop:before>
,<aop:after>
這些。每次遍歷,都會生成一個AbstractBeanDefinition advisorDefinition
,也就是說,每次遍歷都會生成一個bean definition。 -
具體的
<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>
收獲:
-
切點對應的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" }
-
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的時候,有什么特別之處。