Spring4.3.x 浅析xml配置的解析过程(9)——解析aop命名空间之config标签

概述

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

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值