概述
spring爲簡化AOP在xml文件中的定義而創建了一個http://www.springframework.org/schema/aop命名空間,這裏我簡稱爲aop命名空間。spring在解析xml配置文件內容的過程中遇到非默認命名空間時,會查找系統中所有META-INF目錄下的spring.handlers文件中與命名空間對應的處理器,我們可以在spring-aop-x.x.x-RELEASE.jar包的META-INF目錄中的spring.handlers文件可以找到找到aop命名空間的處理器,這個文件的內容如下。
http\://www.springframework.org/schema/aop=org.springframework.aop.config.AopNamespaceHandler
下面是AopNamespaceHandler類的源碼。
public class AopNamespaceHandler extends NamespaceHandlerSupport {
@Override
public void init() {
// 爲config標籤註冊解析器
registerBeanDefinitionParser("config", new ConfigBeanDefinitionParser());
// 爲aspectj-autoproxy標籤註冊解析器
registerBeanDefinitionParser("aspectj-autoproxy", new AspectJAutoProxyBeanDefinitionParser());
// 爲scoped-proxy標籤註冊裝飾器
registerBeanDefinitionDecorator("scoped-proxy", new ScopedProxyBeanDefinitionDecorator());
// 自從spirng2.1開始,spring-configured標籤被定義在content命名空間下
registerBeanDefinitionParser("spring-configured", new SpringConfiguredBeanDefinitionParser());
}
}
AopNamespaceHandler繼承了NamespaceHandlerSupport類,關於這個類的介紹請查看另一篇文章——解析自定義命名空間的標籤。下面我們來直接來看看ConfigBeanDefinitionParser解析器是如何解析config標籤的。
解析<aop:config>標籤
解析器ConfigBeanDefinitionParser直接實現BeanDefinitionParser接口的parse方法,這個方法的源碼如下。
@Override
public BeanDefinition parse(Element element, ParserContext parserContext) {
CompositeComponentDefinition compositeDef =
new CompositeComponentDefinition(element.getTagName(), parserContext.extractSource(element));
parserContext.pushContainingComponent(compositeDef);
// 創建AOP自動代理創建器
configureAutoProxyCreator(parserContext, element);
//遍歷並解析<aop:config>的子標籤
List<Element> childElts = DomUtils.getChildElements(element);
for (Element elt: childElts) {
String localName = parserContext.getDelegate().getLocalName(elt);
if ("pointcut".equals(localName)) {
// 解析<aop:pointcut>標籤
parsePointcut(elt, parserContext);
} else if ("advisor".equals(localName)) {
// 解析<aop:advisor>標籤
parseAdvisor(elt, parserContext);
} else if ("aspect".equals(localName)) {
// 解析<aop:aspect>標籤
parseAspect(elt, parserContext);
}
}
parserContext.popAndRegisterContainingComponent();
return null;
}
parse方法首先調用解析器ConfigBeanDefinitionParser的configureAutoProxyCreator方法來向容器中註冊一個自動代理構建器AspectJAwareAdvisorAutoProxyCreator對象,然後調用parsePointcut方法解析<aop:pointcut>標籤,調用parseAdvisor方法解析<aop:advisor>標籤,調用parseAspect方法解析<aop:aspect>標籤。
1. 創建自動代理構建器對象
下面是ConfigBeanDefinitionParser的configureAutoProxyCreator方法源碼。
private void configureAutoProxyCreator(ParserContext parserContext, Element element) {
AopNamespaceUtils.registerAspectJAutoProxyCreatorIfNecessary(parserContext, element);
}
我們繼續看AOP命名空間工具類AopNamespaceUtils的registerAspectJAutoProxyCreatorIfNecessary方法,源碼如下。
public static void registerAspectJAutoProxyCreatorIfNecessary(
ParserContext parserContext, Element sourceElement) {
// 註冊AspectJ自動代理構建器
BeanDefinition beanDefinition = AopConfigUtils.registerAspectJAutoProxyCreatorIfNecessary(
parserContext.getRegistry(), parserContext.extractSource(sourceElement));
// 解析<aop:config>標籤的proxy-target-class和expose-proxy屬性
useClassProxyingIfNecessary(parserContext.getRegistry(), sourceElement);
registerComponentIfNecessary(beanDefinition, parserContext);
}
registerAspectJAutoProxyCreatorIfNecessary方法分兩步完成AspectJ自動代理構建器的註冊。第一步是註冊AspectJ自動代理構建器,第二步是解析<aop:config>標籤的屬性來設置自動代理構建器的屬性值。下面分別介紹這兩步。
第一步: 註冊AspectJ自動代理構建器
下面是AopConfigUtils工具類的registerAspectJAutoProxyCreatorIfNecessary方法源碼。
public static BeanDefinition registerAspectJAutoProxyCreatorIfNecessary(BeanDefinitionRegistry registry, Object source) {
return registerOrEscalateApcAsRequired(AspectJAwareAdvisorAutoProxyCreator.class, registry, source);
}
繼續看AopConfigUtils工具類的registerOrEscalateApcAsRequired方法,如下源碼。
private static BeanDefinition registerOrEscalateApcAsRequired(Class<?> cls, BeanDefinitionRegistry registry, Object source) {
Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
// 定義有AUTO_PROXY_CREATOR_BEAN_NAME="org.springframework.aop.config.internalAutoProxyCreator"
if (registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME)) {
// 如果容器中已經存在自動代理構建器,則比較兩個構建器的優先級
BeanDefinition apcDefinition = registry.getBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME);
if (!cls.getName().equals(apcDefinition.getBeanClassName())) {
int currentPriority = findPriorityForClass(apcDefinition.getBeanClassName());
int requiredPriority = findPriorityForClass(cls);
// 保存優先級高的構建器
if (currentPriority < requiredPriority) {
apcDefinition.setBeanClassName(cls.getName());
}
}
return null;
}
// 如果容器中還沒有自動代理構建器
// 則創建構建器相應的BeanDefinition對象
RootBeanDefinition beanDefinition = new RootBeanDefinition(cls);
beanDefinition.setSource(source);
beanDefinition.getPropertyValues().add("order", Ordered.HIGHEST_PRECEDENCE);
beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
// 向容器中註冊代理構建器的BeanDefinition對象
registry.registerBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME, beanDefinition);
return beanDefinition;
}
第二步:解析<aop:config>屬性
向容器中註冊完成代理構建器後,接着調用AopNamespaceUtils工具類的useClassProxyingIfNecessary方法解析<aop:config>的兩個屬性,這個方法的源碼如下。
private static void useClassProxyingIfNecessary(BeanDefinitionRegistry registry, Element sourceElement) {
if (sourceElement != null) {
// 解析proxy-target-class屬性
boolean proxyTargetClass = Boolean.valueOf(sourceElement.getAttribute("proxy-target-class"));
if (proxyTargetClass) {
AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
}
// 解析expose-proxy屬性
boolean exposeProxy = Boolean.valueOf(sourceElement.getAttribute("expose-proxy"));
if (exposeProxy) {
AopConfigUtils.forceAutoProxyCreatorToExposeProxy(registry);
}
}
}
下面是AopConfigUtils處理這兩個屬性的方法源碼。
其中AUTO_PROXY_CREATOR_BEAN_NAME=”org.springframework.aop.config.internalAutoProxyCreator”
public static void forceAutoProxyCreatorToUseClassProxying(BeanDefinitionRegistry registry) {
if (registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME)) {
BeanDefinition definition = registry.getBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME);
definition.getPropertyValues().add("proxyTargetClass", Boolean.TRUE);
}
}
public static void forceAutoProxyCreatorToExposeProxy(BeanDefinitionRegistry registry) {
if (registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME)) {
BeanDefinition definition = registry.getBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME);
definition.getPropertyValues().add("exposeProxy", Boolean.TRUE);
}
}
2. 解析<aop:pointcut>標籤
ConfigBeanDefinitionParser解析器調用它的parsePointcut方法解析<aop:pointcut>標籤,這個方法的源碼如下。
private AbstractBeanDefinition parsePointcut(Element pointcutElement, ParserContext parserContext) {
// 獲取id屬性值
String id = pointcutElement.getAttribute("id");
// 獲取expression屬性值
String expression = pointcutElement.getAttribute("expression");
AbstractBeanDefinition pointcutDefinition = null;
try {
this.parseState.push(new PointcutEntry(id));
// 根據切點表達式來創建一個Pointcut對象的BeanDefinition
pointcutDefinition = createPointcutDefinition(expression);
pointcutDefinition.setSource(parserContext.extractSource(pointcutElement));
String pointcutBeanName = id;
if (StringUtils.hasText(pointcutBeanName)) {
// id屬性值不爲空時,使用id值爲Pointcut的bean名稱,並註冊到容器中
parserContext.getRegistry().registerBeanDefinition(pointcutBeanName, pointcutDefinition);
} else {
// id屬性值爲空時,使用bean名稱生成器來爲Pointcut創建bean名稱,並註冊到容器中
pointcutBeanName = parserContext.getReaderContext().registerWithGeneratedName(pointcutDefinition);
}
parserContext.registerComponent(
new PointcutComponentDefinition(pointcutBeanName, pointcutDefinition, expression));
} finally {
this.parseState.pop();
}
return pointcutDefinition;
}
現在看看ConfigBeanDefinitionParser解析器的createPointcutDefinition方法到底創建一個怎麼樣的BeanDefinition,源碼如下。
protected AbstractBeanDefinition createPointcutDefinition(String expression) {
RootBeanDefinition beanDefinition = new RootBeanDefinition(AspectJExpressionPointcut.class);
// 指定創建一個作用域爲prototype的AspectJExpressionPointcut對象
beanDefinition.setScope(BeanDefinition.SCOPE_PROTOTYPE);
beanDefinition.setSynthetic(true);
beanDefinition.getPropertyValues().add("expression", expression);
return beanDefinition;
}
createPointcutDefinition方法向容器中註冊一個AspectJExpressionPointcut對象。
3. 解析<aop:advisor>標籤
ConfigBeanDefinitionParser解析器調用它的parseAdvisor方法解析<advisor>標籤,這個方法的源碼如下。
private void parseAdvisor(Element advisorElement, ParserContext parserContext) {
// 創建一個Advisor對象對應的BeanDefintion對象
AbstractBeanDefinition advisorDef = createAdvisorBeanDefinition(advisorElement, parserContext);
// 獲取id屬性值
String id = advisorElement.getAttribute(ID);
try {
this.parseState.push(new AdvisorEntry(id));
String advisorBeanName = id;
if (StringUtils.hasText(advisorBeanName)) {
// id屬性值不爲空時,使用id值爲Advisor的bean名稱,並註冊到容器中
parserContext.getRegistry().registerBeanDefinition(advisorBeanName, advisorDef);
} else {
// id屬性值爲空時,使用bean名稱生成器來爲Advisor創建bean名稱,並註冊到容器中
advisorBeanName = parserContext.getReaderContext().registerWithGeneratedName(advisorDef);
}
// 獲取Advisor的Pointcut
// 解析pointcut和poincut-ref屬性
Object pointcut = parsePointcutProperty(advisorElement, parserContext);
if (pointcut instanceof BeanDefinition) {
// 獲取的是一個根據pointcut屬性所指定的切點表達式來創建的的一個Poincut bean
advisorDef.getPropertyValues().add("pointcut", pointcut);
parserContext.registerComponent(
new AdvisorComponentDefinition(advisorBeanName, advisorDef, (BeanDefinition) pointcut));
} else if (pointcut instanceof String) {
// 獲取的是pointcut-ref屬性值指向的一個Pointcut bean。
advisorDef.getPropertyValues().add("pointcut", new RuntimeBeanReference((String) pointcut));
parserContext.registerComponent(
new AdvisorComponentDefinition(advisorBeanName, advisorDef));
}
} finally {
this.parseState.pop();
}
}
parseAdvisor方法可以分成兩步來解讀,第一步是創建並註冊Advisor對應的BeanDefintion對象,這一步中創建是通過調用ConfigBeanDefinitionParser的createAdvisorBeanDefinition方法完成;第二步是通過解析pointcut或者pointcut-ref屬性來獲取Advisor的Pointcut,這一步是通過調用ConfigBeanDefinitionParser的parsePointcutProperty方法來完成。下面我們分別看看這兩個方法的代碼。
第一步 創建Advisor對應的BeanDefinition
parseAdvisor方法調用ConfigBeanDefinitionParser的createAdvisorBeanDefinition來創建一個BeanDefinition對象來指定將被創建的Adisor對象,源碼如下。
private AbstractBeanDefinition createAdvisorBeanDefinition(Element advisorElement, ParserContext parserContext) {
// 指定向容器中注入DefaultBeanFactoryPointcutAdvisor對象作爲Advisor
RootBeanDefinition advisorDefinition = new RootBeanDefinition(DefaultBeanFactoryPointcutAdvisor.class);
advisorDefinition.setSource(parserContext.extractSource(advisorElement));
// 指定Advisor的Advice對象
// 獲取advice-ref屬性值
String adviceRef = advisorElement.getAttribute("advice-ref");
if (!StringUtils.hasText(adviceRef)) {
parserContext.getReaderContext().error(
"'advice-ref' attribute contains empty value.", advisorElement, this.parseState.snapshot());
}
else {
advisorDefinition.getPropertyValues().add(
"adviceBeanName", new RuntimeBeanNameReference(adviceRef));
}
// 獲取order值,用於指定Advise的執行順序
if (advisorElement.hasAttribute("order")) {
advisorDefinition.getPropertyValues().add(
"order", advisorElement.getAttribute("order"));
}
return advisorDefinition;
}
createAdvisorBeanDefinition方法不僅是創建了一個與Advisor有關的BeanDefinitiion對象,還獲取了<aop:advisor>標籤的order和adice-ref屬性來設置Advisor的相應屬性。
第二步 獲取Advisor的Pointcut
<aop:advisor>有id、advice-ref、order、pointcut和pointcut-ref共5個屬性,其中前三個屬性只需要簡單獲取屬性值就OK了,而parseAdvisor方法還需調用ConfigBeanDefinitionParser的parsePointcutProperty方法來解析pointcut和pointcut-ref屬性,下面是這個方法的源碼。
private Object parsePointcutProperty(Element element, ParserContext parserContext) {
// poincut和pointcut-ref屬性不能同時定義
if (element.hasAttribute("pointcut") && element.hasAttribute("pointcut-ref")) {
parserContext.getReaderContext().error(
"Cannot define both 'pointcut' and 'pointcut-ref' on <advisor> tag.",
element, this.parseState.snapshot());
return null;
} else if (element.hasAttribute("pointcut")) {
String expression = element.getAttribute("pointcut");
// 根據切點表達式來創建一個Pointcut的BeanDefinition對象
AbstractBeanDefinition pointcutDefinition = createPointcutDefinition(expression);
pointcutDefinition.setSource(parserContext.extractSource(element));
return pointcutDefinition;
} else if (element.hasAttribute("pointcut-ref")) {
// 獲取pointcut-ref屬性值並返回
String pointcutRef = element.getAttribute("pointcut-ref");
if (!StringUtils.hasText(pointcutRef)) {
parserContext.getReaderContext().error(
"'pointcut-ref' attribute contains empty value.", element, this.parseState.snapshot());
return null;
}
return pointcutRef;
} else {
parserContext.getReaderContext().error(
"Must define one of 'pointcut' or 'pointcut-ref' on <advisor> tag.",
element, this.parseState.snapshot());
return null;
}
}
4. 解析<aop:aspect>標籤
ConfigBeanDefinitionParser解析器調用它的parseAspect方法解析<aop:aspect>標籤,這個方法的源碼如下。
private void parseAspect(Element aspectElement, ParserContext parserContext) {
// 獲取id屬性值
String aspectId = aspectElement.getAttribute("id");
// 獲取ref屬性值
String aspectName = aspectElement.getAttribute("ref");
try {
this.parseState.push(new AspectEntry(aspectId, aspectName));
List<BeanDefinition> beanDefinitions = new ArrayList<BeanDefinition>();
List<BeanReference> beanReferences = new ArrayList<BeanReference>();
List<Element> declareParents = DomUtils.getChildElementsByTagName(aspectElement, "declare-parents");
// 遍歷並解析<aop:declare-parents>標籤
// 定義有METHOD_INDEX=0
for (int i = METHOD_INDEX; i < declareParents.size(); i++) {
Element declareParentsElement = declareParents.get(i);
// 解析<aop:declare-parents>標籤
beanDefinitions.add(parseDeclareParents(declareParentsElement, parserContext));
}
// 遍歷並解析before、after、after-returning、after-throwing和around標籤
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;
if (!StringUtils.hasText(aspectName)) {
parserContext.getReaderContext().error(
"<aspect> tag needs aspect bean reference via 'ref' attribute when declaring advices.",
aspectElement, this.parseState.snapshot());
return;
}
beanReferences.add(new RuntimeBeanReference(aspectName));
}
// 解析adice相關的標籤,並創建和註冊相應的BeanDefinition對象
AbstractBeanDefinition advisorDefinition = parseAdvice(
aspectName, i, aspectElement, (Element) node, parserContext, beanDefinitions, beanReferences);
beanDefinitions.add(advisorDefinition);
}
}
AspectComponentDefinition aspectComponentDefinition = createAspectComponentDefinition(
aspectElement, aspectId, beanDefinitions, beanReferences, parserContext);
parserContext.pushContainingComponent(aspectComponentDefinition);
// 遍歷並解析<aop:pointcut>標籤
List<Element> pointcuts = DomUtils.getChildElementsByTagName(aspectElement, POINTCUT);
for (Element pointcutElement : pointcuts) {
parsePointcut(pointcutElement, parserContext);
}
parserContext.popAndRegisterContainingComponent();
} finally {
this.parseState.pop();
}
}
parseAspect方法解析aspect標籤下的pointcut、declare-parents和5個advice標籤,其中pointcut標籤的解析已經在前面看過了,這裏我們只需要看後面兩種標籤的解析。
(1)解析<aop:declare-parents>標籤。parseAspect調用ConfigBeanDefinitionParser解析器的parseDeclareParents方法來處理此標籤,代碼如下。
private AbstractBeanDefinition parseDeclareParents(Element declareParentsElement, ParserContext parserContext) {
// 使用BeanDefinitionBuilder對象來構造一個BeanDefinition對象
BeanDefinitionBuilder builder = BeanDefinitionBuilder.rootBeanDefinition(DeclareParentsAdvisor.class);
builder.addConstructorArgValue(declareParentsElement.getAttribute("implement-interface"));
builder.addConstructorArgValue(declareParentsElement.getAttribute("types-matching"));
String defaultImpl = declareParentsElement.getAttribute("default-impl");
String delegateRef = declareParentsElement.getAttribute("delegate-ref");
// default-impl和delegate-ref不能同時定義
if (StringUtils.hasText(defaultImpl) && !StringUtils.hasText(delegateRef)) {
builder.addConstructorArgValue(defaultImpl);
} else if (StringUtils.hasText(delegateRef) && !StringUtils.hasText(defaultImpl)) {
builder.addConstructorArgReference(delegateRef);
} else {
parserContext.getReaderContext().error(
"Exactly one of the " + DEFAULT_IMPL + " or " + DELEGATE_REF + " attributes must be specified",
declareParentsElement, this.parseState.snapshot());
}
AbstractBeanDefinition definition = builder.getBeanDefinition();
definition.setSource(parserContext.extractSource(declareParentsElement));
// 向容器註冊BeanDefinitiion對象
parserContext.getReaderContext().registerWithGeneratedName(definition);
return definition;
}
parseDeclareParents方法作用是向容器註冊一個DeclareParentsAdvisor對象。
(2)解析advice標籤。spring提供了<aop:before>、<aop:after>、<aop:after-returning>、<aop:after-throwing>、<aop:around>5個advice標籤,parseAspect調用ConfigBeanDefinitionParser解析器的parseAdvice方法來處理這些標籤,代碼如下。
private AbstractBeanDefinition parseAdvice(
String aspectName, int order, Element aspectElement, Element adviceElement, ParserContext parserContext,
List<BeanDefinition> beanDefinitions, List<BeanReference> beanReferences) {
try {
this.parseState.push(new AdviceEntry(parserContext.getDelegate().getLocalName(adviceElement)));
// 創建一個方法工廠bean
RootBeanDefinition methodDefinition = new RootBeanDefinition(MethodLocatingFactoryBean.class);
methodDefinition.getPropertyValues().add("targetBeanName", aspectName);
methodDefinition.getPropertyValues().add("methodName", adviceElement.getAttribute("method"));
methodDefinition.setSynthetic(true);
// 創建一個用於獲取aspect實例的工廠
RootBeanDefinition aspectFactoryDef =
new RootBeanDefinition(SimpleBeanFactoryAwareAspectInstanceFactory.class);
aspectFactoryDef.getPropertyValues().add("aspectBeanName", aspectName);
aspectFactoryDef.setSynthetic(true);
// 創建Advice
AbstractBeanDefinition adviceDef = createAdviceDefinition(
adviceElement, parserContext, aspectName, order, methodDefinition, aspectFactoryDef,
beanDefinitions, beanReferences);
// 配置Advicor
RootBeanDefinition advisorDefinition = new RootBeanDefinition(AspectJPointcutAdvisor.class);
advisorDefinition.setSource(parserContext.extractSource(adviceElement));
advisorDefinition.getConstructorArgumentValues().addGenericArgumentValue(adviceDef);
if (aspectElement.hasAttribute("order")) {
advisorDefinition.getPropertyValues().add(
"order", aspectElement.getAttribute("order"));
}
// 向容器中註冊Advisor
parserContext.getReaderContext().registerWithGeneratedName(advisorDefinition);
return advisorDefinition;
} finally {
this.parseState.pop();
}
}
parseAdvice方法首先創建一個用於獲取指定aspect實例方法的MethodLocatingFactoryBean對應的BeanDefinition,然後創建一個用於獲取指定aspect實例的SimpleBeanFactoryAwareAspectInstanceFactory對應的BeanDefinition,接着調用ConfigBeanDefinitionParser解析器的createAdviceDefinition方法創建Advice的BeanDefinition,最後創建並註冊一個Advisor的BeanDefition。這些步驟中我們還需要看看createAdviceDefinition方法是如何創建Advice的BeanDefintion,下面是這個方法的源碼。
private AbstractBeanDefinition createAdviceDefinition(
Element adviceElement, ParserContext parserContext, String aspectName, int order,
RootBeanDefinition methodDef, RootBeanDefinition aspectFactoryDef,
List<BeanDefinition> beanDefinitions, List<BeanReference> beanReferences) {
RootBeanDefinition adviceDefinition = new RootBeanDefinition(getAdviceClass(adviceElement, parserContext));
adviceDefinition.setSource(parserContext.extractSource(adviceElement));
adviceDefinition.getPropertyValues().add("aspectName", aspectName);
adviceDefinition.getPropertyValues().add("declarationOrder", order);
if (adviceElement.hasAttribute("returning")) {
adviceDefinition.getPropertyValues().add(
"returningName", adviceElement.getAttribute("returning"));
}
if (adviceElement.hasAttribute("throwing")) {
adviceDefinition.getPropertyValues().add(
"throwingName", adviceElement.getAttribute("throwing"));
}
if (adviceElement.hasAttribute("arg-names")) {
adviceDefinition.getPropertyValues().add(
"argumentNames", adviceElement.getAttribute("arg-names"));
}
ConstructorArgumentValues cav = adviceDefinition.getConstructorArgumentValues();
// 定義有METHOD_INDEX=0
cav.addIndexedArgumentValue(METHOD_INDEX, methodDef);
// 解析poincut和pointcut-ref屬性
// 定義有POINTCUT_INDEX = 1
Object pointcut = parsePointcutProperty(adviceElement, parserContext);
if (pointcut instanceof BeanDefinition) {
cav.addIndexedArgumentValue(POINTCUT_INDEX, pointcut);
beanDefinitions.add((BeanDefinition) pointcut);
} else if (pointcut instanceof String) {
RuntimeBeanReference pointcutRef = new RuntimeBeanReference((String) pointcut);
cav.addIndexedArgumentValue(POINTCUT_INDEX, pointcutRef);
beanReferences.add(pointcutRef);
}
// 定義有ASPECT_INSTANCE_FACTORY_INDEX = 2
cav.addIndexedArgumentValue(ASPECT_INSTANCE_FACTORY_INDEX, aspectFactoryDef);
return adviceDefinition;
}
createAdviceDefinition方法主要是解析adive標籤上的屬性值。不過在處理屬性之前,還需要判斷標籤類型是5中advice標籤中的哪種,下面是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".equals(elementName)) {
return AspectJAfterReturningAdvice.class;
} else if ("after-throwing".equals(elementName)) {
return AspectJAfterThrowingAdvice.class;
} else if ("around".equals(elementName)) {
return AspectJAroundAdvice.class;
} else {
throw new IllegalArgumentException("Unknown advice kind [" + elementName + "].");
}
}
至此,我們就完成了探索spring遇到aop命名空間下的config標籤時會創建哪些類型對應的BeanDefiniton。
總結
(1)對config標籤創建AOP自動代理創建器AspectJAwareAdvisorAutoProxyCreator對象的BeanDefinition。
如果spring容器中中已經存在了一個”org.springframework.aop.config.internalAutoProxyCreator”,就比較兩個創建器的優先級,優先級高的被保存,低的被從容器中移除。
(2)對pointcut標籤創建AspectJExpressionPointcut對象的BeanDefiniton。
pointcut標籤必須要提供expression屬性值。
(3)對advisor標籤創建一個DefaultBeanFactoryPointcutAdvisor對象的BeanDefinition。
advisor標籤還需要一個實現了Adivce接口的bean,通過adive-ref屬性指定;以及需要一個Pointcut bean,通過pointcut或者pointcut-ref屬性指定。
(4)對aspect標籤不會創建BeanDefintion,它的作用是爲advice類型的標籤提供aspect方法。
(6)對advice類型的標籤會創建相應的BeanDefintion,如下。
對before標籤創建AspectJMethodBeforeAdvice對象的BeanDefintion。
對after標籤創建AspectJAfterAdvice對象的BeanDefinition。
對after-returning標籤創建AspectJAfterReturningAdvice對象的BeanDefinition。
對after-throwing標籤創建AspectJAfterThrowingAdvice對象的BeanDefinition。
對around標籤創建AspectJAroundAdvice對象的BeanDefinition。
這些Advice的創建還需要MethodLocatingFactoryBean對象和SimpleBeanFactoryAwareAspectInstanceFactory對象,因此,spring還需要創建MethodLocatingFactoryBean對象和SimpleBeanFactoryAwareAspectInstanceFactory對象的BeanDefinition。
最後創建AspectJPointcutAdvisor對象的BeanDefinition來管理Advice的BeanDefinition。
(5)對declare-parents標籤創建DeclareParentsAdvisor對象的BeanDefinition