Spring4.3.x 淺析xml配置的解析過程(9)——解析aop命名空間之config標籤

版權聲明:本文爲博主原創文章,未經博主允許不得轉載。 https://blog.csdn.net/chyohn/article/details/54945999

概述

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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章