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標簽的。
解析器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>標簽。
下面是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); } }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對象。
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; } }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
新聞熱點
疑難解答