Spring AOP

7.SpringAop之声明式Aop基于配置:AspectJAw

2018-07-10  本文已影响43人  土豆肉丝盖浇饭

介绍

AspectJ项目是对java语言面向切面编程的一个扩展,Spring框架实现了AspectJ的部分功能。AspectJ最大的特点就是,对连接点的配置采用了AspectJ的表达式,在Spring框架中实现的最常用的表达式是execution表达式。
翻阅了一下aspectj文档,发现aspectj的示例代码全是Scala 的。根据spring框架的底层架构,估计也只能实现这部分。对于java语言而言,说不定都能实现。具体aspectj其他的有用的表达式可以去,aspectj的官网看看。对于我们日常编程而言,spring实现的也够用了。或者,我们可以转战Scala。

AspectJ基于xml配置的aop生效通过AspectJAwareAdvisorAutoProxyCreator这个类,下面我们来仔细分析下这个类

类继承结构

image.png

可以看到它继承了AbstractAdivisorAutoProxyCreator,也就是说子类只需要关注如何取到有效的Adivisor即可

使用

在讲解源码前,先介绍一下使用,对于xml模式,我们需要增加对应的xml配置如下

<aop:config>
        <aop:pointcut id="pointcut" expression="execution(* *.hello(..))"/>
        <aop:pointcut id="pointcut2" expression="execution(* *.hello(..))"/>
        <aop:aspect ref="testAspect"  >
            <aop:before method="before" pointcut-ref="pointcut"/>
            <aop:after method="after" pointcut-ref="pointcut"/>
        </aop:aspect>
        <!--测试基于注解的切面 -->
        <aop:aspect ref="testAspect">
            <aop:before method="before" pointcut-ref="pointcut2"/>
            <aop:after method="after" pointcut-ref="pointcut2"/>
        </aop:aspect>
    </aop:config>

其中testAspect的before和after方法对应切面增强逻辑,在spring配置文件中增加了上述配置后,对应pointcut匹配的方法就会增加对应的增强逻辑

生成Advisor

AspectJAwareAdvisorAutoProxyCreator内的逻辑并不复杂,主要逻辑在如何通过xml配置生成对应的Advisor BeanDefinition到spring容器中去

首先我们要通过自定义的spring handler处理aop命名空间的xml配置,在spring-aop-*.jar的META-INF/spring.handlers文件中配置

http\://www.springframework.org/schema/aop=org.springframework.aop.config.AopNamespaceHandler

看下AopNamespaceHandler的实现

public class AopNamespaceHandler extends NamespaceHandlerSupport {

    /**
     * Register the {@link BeanDefinitionParser BeanDefinitionParsers} for the
     * '{@code config}', '{@code spring-configured}', '{@code aspectj-autoproxy}'
     * and '{@code scoped-proxy}' tags.
     */
    @Override
    public void init() {
        // In 2.0 XSD as well as in 2.1 XSD.
        registerBeanDefinitionParser("config", new ConfigBeanDefinitionParser());
        registerBeanDefinitionParser("aspectj-autoproxy", new AspectJAutoProxyBeanDefinitionParser());
        registerBeanDefinitionDecorator("scoped-proxy", new ScopedProxyBeanDefinitionDecorator());

        // Only in 2.0 XSD: moved to context namespace as of 2.1
        registerBeanDefinitionParser("spring-configured", new SpringConfiguredBeanDefinitionParser());
    }

}

这边我们只需要关注config的ConfigBeanDefinitionParser
先看下BeanDefinitionParser接口定义

public interface BeanDefinitionParser {

    /**
     * Parse the specified {@link Element} and register the resulting
     * {@link BeanDefinition BeanDefinition(s)} with the
     * {@link org.springframework.beans.factory.xml.ParserContext#getRegistry() BeanDefinitionRegistry}
     * embedded in the supplied {@link ParserContext}.
     * <p>Implementations must return the primary {@link BeanDefinition} that results
     * from the parse if they will ever be used in a nested fashion (for example as
     * an inner tag in a {@code <property/>} tag). Implementations may return
     * {@code null} if they will <strong>not</strong> be used in a nested fashion.
     * @param element the element that is to be parsed into one or more {@link BeanDefinition BeanDefinitions}
     * @param parserContext the object encapsulating the current state of the parsing process;
     * provides access to a {@link org.springframework.beans.factory.support.BeanDefinitionRegistry}
     * @return the primary {@link BeanDefinition}
     */
    BeanDefinition parse(Element element, ParserContext parserContext);

}

主要就是一个解析方法,把xml对应的element解析为BeanDefinition
那么从ConfigBeanDefinitionParser的parse方法分析起来

public BeanDefinition parse(Element element, ParserContext parserContext) {
        CompositeComponentDefinition compositeDef =
                new CompositeComponentDefinition(element.getTagName(), parserContext.extractSource(element));
        parserContext.pushContainingComponent(compositeDef);

        configureAutoProxyCreator(parserContext, element);

        List<Element> childElts = DomUtils.getChildElements(element);
        for (Element elt: childElts) {
            String localName = parserContext.getDelegate().getLocalName(elt);
            if (POINTCUT.equals(localName)) {
                parsePointcut(elt, parserContext);
            }
            else if (ADVISOR.equals(localName)) {
                parseAdvisor(elt, parserContext);
            }
            else if (ASPECT.equals(localName)) {
                parseAspect(elt, parserContext);
            }
        }

        parserContext.popAndRegisterContainingComponent();
        return null;
    }

通过上面代码,可以发现,aop:config元素有三种子节点,pointcut,adivisor以及aspect,分别对应切入点,通知器以及切面。advisor是spring内部自定义类型,也是我们需要产生的类型,pointcut和aspect其实也是用来生成adivsor的

同时我们也注意到configureAutoProxyCreator(parserContext, element);
这句代码会给我们在spring容器加入AspectJAwareAdvisorAutoProxyCreator的beandefinition,也就是说用aop:config后,我们不用在配置文件增加AspectJAwareAdvisorAutoProxyCreator的bean配置

下面分别介绍advisor,ponitcut,aspect的解析逻辑

advisor元素解析

首先看下advisor在xsd中的规则

xsd规范

<xsd:complexType name="advisorType">
    <xsd:attribute name="id" type="xsd:string"/>
    <xsd:attribute name="advice-ref" type="xsd:string" use="required">
    </xsd:attribute>
    <xsd:attribute name="pointcut" type="xsd:string">
    </xsd:attribute>
    <xsd:attribute name="pointcut-ref" type="pointcutRefType">
    </xsd:attribute>
    <xsd:attribute name="order" type="xsd:token">
    </xsd:attribute>
</xsd:complexType>

<xsd:simpleType name="pointcutRefType">
    <xsd:union memberTypes="xsd:string"/>
</xsd:simpleType>

为了方便查看结构,我删除了<xsd:annotation>标签,这个标签相当于注释

同时我们可以发现,<aop:adivisor> 可以包括id,advice-ref,pointcut,pointcut-ref,order这些属性,没有子元素

解析逻辑

private void parseAdvisor(Element advisorElement, ParserContext parserContext) {
    //创建Adivisor的BeanDefinition
    AbstractBeanDefinition advisorDef = createAdvisorBeanDefinition(advisorElement, parserContext);
    String id = advisorElement.getAttribute(ID);

    try {
        this.parseState.push(new AdvisorEntry(id));
        String advisorBeanName = id;
                //将advisorDef预先放入BeanFactory,如果没有id,生成默认名字
        if (StringUtils.hasText(advisorBeanName)) {
            parserContext.getRegistry().registerBeanDefinition(advisorBeanName, advisorDef);
        }
        else {
            advisorBeanName = parserContext.getReaderContext().registerWithGeneratedName(advisorDef);
        }

        //解析pointcut相关属性
        Object pointcut = parsePointcutProperty(advisorElement, parserContext);
                //如果配置了pointcut属性,会在parsePointcutProperty方法解析为BeanDefinition
        if (pointcut instanceof BeanDefinition) {
            advisorDef.getPropertyValues().add(POINTCUT, pointcut);
            parserContext.registerComponent(
                    new AdvisorComponentDefinition(advisorBeanName, advisorDef, (BeanDefinition) pointcut));
        }
                //如果配置了pointcut-ref属性,对advisorDef增加RuntimeBeanReference即可
        else if (pointcut instanceof String) {
            advisorDef.getPropertyValues().add(POINTCUT, new RuntimeBeanReference((String) pointcut));
            parserContext.registerComponent(
                    new AdvisorComponentDefinition(advisorBeanName, advisorDef));
        }
    }
    finally {
        this.parseState.pop();
    }
}

在方法的开始会创建DefaultBeanFactoryPointcutAdvisor类型的RootBeanDefinition,DefaultBeanFactoryPointcutAdvisor类这个Advisor类的不同之处在于如果没有配置advice,它会根据advice-ref从beanfactory获取,在现在的场景下,advice就是没有设置的,所有advice实现都会根据advice-ref从beanfactory获取。详细实现,大家可以自己看下源码。
如上所述,在createAdvisorBeanDefinition会设置advice-ref和order两个属性

private AbstractBeanDefinition createAdvisorBeanDefinition(Element advisorElement, ParserContext parserContext) {
    //创建DefaultBeanFactoryPointcutAdvisor类型的RootBeanDefinition
    RootBeanDefinition advisorDefinition = new RootBeanDefinition(DefaultBeanFactoryPointcutAdvisor.class);
    advisorDefinition.setSource(parserContext.extractSource(advisorElement));

    //设置adviceRef属性,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(
                ADVICE_BEAN_NAME, new RuntimeBeanNameReference(adviceRef));
    }
    //设置order属性
    if (advisorElement.hasAttribute(ORDER_PROPERTY)) {
        advisorDefinition.getPropertyValues().add(
                ORDER_PROPERTY, advisorElement.getAttribute(ORDER_PROPERTY));
    }

    return advisorDefinition;
}

之后会根据pointcut和pointcut-ref属性对DefaultBeanFactoryPointcutAdvisor进行配置,逻辑在parsePointcutProperty方法

private Object parsePointcutProperty(Element element, ParserContext parserContext) {
    //pointcut和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;
    }
    //如果配置了pointcut,pointcut内的内容对应aspectj表达式,需要新建pointcut的BeanDefinition
    else if (element.hasAttribute(POINTCUT)) {
        // Create a pointcut for the anonymous pc and register it.
        String expression = element.getAttribute(POINTCUT);
        AbstractBeanDefinition pointcutDefinition = createPointcutDefinition(expression);
        pointcutDefinition.setSource(parserContext.extractSource(element));
        return pointcutDefinition;
    }
    //如果配置了pointcut-ref,直接返回内容,会在外层创建RuntimeBeanReference属性
    else if (element.hasAttribute(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;
    }
}

创建pointcut类型的BeanDefinition的方法createPointcutDefinition在下节pointcut元素解析讲

在上述代码中我们可以发现 parserContext.registerComponent这个逻辑,这部分的代码是为了在该元素完成解析的时候做事件通知所用,不影响我们往BeanFactory放BeanDefinition的逻辑,所以请忽略。

ponitcut元素解析

xsd规范

<xsd:complexType name="pointcutType">
    <xsd:attribute name="id" type="xsd:string" use="required">
    </xsd:attribute>
    <xsd:attribute name="expression" use="required" type="xsd:string">
    </xsd:attribute>
</xsd:complexType>

pointcut标签很简单,就id和expression两个属性,解析逻辑也不复杂

解析逻辑

private AbstractBeanDefinition parsePointcut(Element pointcutElement, ParserContext parserContext) {
    String id = pointcutElement.getAttribute(ID);
    String expression = pointcutElement.getAttribute(EXPRESSION);

    AbstractBeanDefinition pointcutDefinition = null;

    try {
        this.parseState.push(new PointcutEntry(id));
        //根据expression创建切入点
        pointcutDefinition = createPointcutDefinition(expression);
        pointcutDefinition.setSource(parserContext.extractSource(pointcutElement));

        String pointcutBeanName = id;
        //注册到BeanFactory
        if (StringUtils.hasText(pointcutBeanName)) {
            parserContext.getRegistry().registerBeanDefinition(pointcutBeanName, pointcutDefinition);
        }
        else {
            pointcutBeanName = parserContext.getReaderContext().registerWithGeneratedName(pointcutDefinition);
        }

        parserContext.registerComponent(
                new PointcutComponentDefinition(pointcutBeanName, pointcutDefinition, expression));
    }
    finally {
        this.parseState.pop();
    }

    return pointcutDefinition;
}

主要逻辑在createPointcutDefinition这个创建BeanDefinition方法上

protected AbstractBeanDefinition createPointcutDefinition(String expression) {
    RootBeanDefinition beanDefinition = new RootBeanDefinition(AspectJExpressionPointcut.class);
    beanDefinition.setScope(BeanDefinition.SCOPE_PROTOTYPE);
    beanDefinition.setSynthetic(true);
    beanDefinition.getPropertyValues().add(EXPRESSION, expression);
    return beanDefinition;
}

注意到创建了AspectJExpressionPointcut类型的RootBeanDefinition,同时scope为prototype,因为这种类型的BeanDefinition会存在很多个吧,只是表达式不一样

一路看一下来都很简单,但是这个AspectJExpressionPointcut不简单,它的功能是根据配置的表达式去匹配连接点,也就是我们的方法。我们只要知道它功能即可,想看懂还真不容易。

aspect元素解析

xsd规范

<xsd:complexType name="aspectType">
    <xsd:choice minOccurs="0" maxOccurs="unbounded">
        <xsd:element name="pointcut" type="pointcutType">
        </xsd:element>
        <xsd:element name="declare-parents" type="declareParentsType">
        </xsd:element>
        <xsd:element name="before" type="basicAdviceType">
        </xsd:element>
        <xsd:element name="after" type="basicAdviceType">
        </xsd:element>
        <xsd:element name="after-returning" type="afterReturningAdviceType">
        </xsd:element>
        <xsd:element name="after-throwing" type="afterThrowingAdviceType">
        </xsd:element>
        <xsd:element name="around" type="basicAdviceType">
        </xsd:element>
    </xsd:choice>
    <xsd:attribute name="id" type="xsd:string">
    </xsd:attribute>
    <xsd:attribute name="ref" type="xsd:string">
    </xsd:attribute>
    <xsd:attribute name="order" type="xsd:token">
    </xsd:attribute>
</xsd:complexType>

<xsd:complexType name="basicAdviceType">
    <xsd:attribute name="pointcut" type="xsd:string">
    </xsd:attribute>
    <xsd:attribute name="pointcut-ref" type="pointcutRefType">
    </xsd:attribute>
    <xsd:attribute name="method" type="xsd:string" use="required">
    </xsd:attribute>
    <xsd:attribute name="arg-names" type="xsd:string">
    </xsd:attribute>
</xsd:complexType>

<xsd:complexType name="afterReturningAdviceType">
    <xsd:complexContent>
        <xsd:extension base="basicAdviceType">
            <xsd:attribute name="returning" type="xsd:string">
            </xsd:attribute>
        </xsd:extension>
    </xsd:complexContent>
</xsd:complexType>

<xsd:complexType name="afterThrowingAdviceType">
    <xsd:complexContent>
        <xsd:extension base="basicAdviceType">
            <xsd:attribute name="throwing" type="xsd:string">
            </xsd:attribute>
        </xsd:extension>
    </xsd:complexContent>
</xsd:complexType>

可以从上面的xsd规范中看到,一个aspect标签有id,ref,order三个属性,可以包含一个或多个ponitcut以及5种advice的子元素。declare-parents目前不知道干嘛用

解析逻辑

private void parseAspect(Element aspectElement, ParserContext parserContext) {
    String aspectId = aspectElement.getAttribute(ID);
    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);
        for (int i = METHOD_INDEX; i < declareParents.size(); i++) {
            Element declareParentsElement = declareParents.get(i);
            beanDefinitions.add(parseDeclareParents(declareParentsElement, parserContext));
        }

        // We have to parse "advice" and all the advice kinds in one loop, to get the
        // ordering semantics right.
        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;
                    //aspect标签的ref属性需要配置,因为advice方法是从ref对应的对象中获取,如果子元素存在advice配置,aspect没有配置ref,那么报错
                    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));
                }
                //每个advice都会生成一个advisorDefinition
                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);

        //获取子元素中的pointcut标签并且解析
        List<Element> pointcuts = DomUtils.getChildElementsByTagName(aspectElement, POINTCUT);
        for (Element pointcutElement : pointcuts) {
            //逻辑和解析pointcut标签一致
            parsePointcut(pointcutElement, parserContext);
        }

        parserContext.popAndRegisterContainingComponent();
    }
    finally {
        this.parseState.pop();
    }
}

针对一个Aspect,里面可能会存在多个advice,在spring框架里面会对应生成多个Adivisor,然后在对目标方法切入的时候,这些adivisior会生成拦截器链

下面看下怎么把advice转换成Adivisor的BeanDefinition

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)));

        // create the method factory bean
        // methodDefinition对应的MethodLocatingFactoryBean用来获取aspect对应方法的Method对象
        RootBeanDefinition methodDefinition = new RootBeanDefinition(MethodLocatingFactoryBean.class);
        methodDefinition.getPropertyValues().add("targetBeanName", aspectName);
        methodDefinition.getPropertyValues().add("methodName", adviceElement.getAttribute("method"));
        methodDefinition.setSynthetic(true);

        // create instance factory definition
        // 用来从spring容器获取对应aspect对象
        RootBeanDefinition aspectFactoryDef =
                new RootBeanDefinition(SimpleBeanFactoryAwareAspectInstanceFactory.class);
        aspectFactoryDef.getPropertyValues().add("aspectBeanName", aspectName);
        aspectFactoryDef.setSynthetic(true);

        // register the pointcut
        // 通过上面2个BeanDefinition生成adviceDef对应的BeanDefinition
        AbstractBeanDefinition adviceDef = createAdviceDefinition(
                adviceElement, parserContext, aspectName, order, methodDefinition, aspectFactoryDef,
                beanDefinitions, beanReferences);

        // configure the advisor
        // 创建advisorDefinition,设置advice属性
        RootBeanDefinition advisorDefinition = new RootBeanDefinition(AspectJPointcutAdvisor.class);
        advisorDefinition.setSource(parserContext.extractSource(adviceElement));
        advisorDefinition.getConstructorArgumentValues().addGenericArgumentValue(adviceDef);
        if (aspectElement.hasAttribute(ORDER_PROPERTY)) {
            advisorDefinition.getPropertyValues().add(
                    ORDER_PROPERTY, aspectElement.getAttribute(ORDER_PROPERTY));
        }

        // register the final advisor
        // 把BeanDefinition放入到Beanfactory
        parserContext.getReaderContext().registerWithGeneratedName(advisorDefinition);

        return advisorDefinition;
    }
    finally {
        this.parseState.pop();
    }
}

上面的方法会生成我们需要的Adivisor的BeanDefinition并且放入到Beanfactory,创建Advice BeanDefinition在createAdviceDefinition方法中

private AbstractBeanDefinition createAdviceDefinition(
            Element adviceElement, ParserContext parserContext, String aspectName, int order,
            RootBeanDefinition methodDef, RootBeanDefinition aspectFactoryDef,
            List<BeanDefinition> beanDefinitions, List<BeanReference> beanReferences) {

    //getAdviceClass方法用于获取advice的class
    RootBeanDefinition adviceDefinition = new RootBeanDefinition(getAdviceClass(adviceElement, parserContext));
    adviceDefinition.setSource(parserContext.extractSource(adviceElement));
    //设置aspectname属性
    adviceDefinition.getPropertyValues().add(ASPECT_NAME_PROPERTY, aspectName);
    //设置order属性
    adviceDefinition.getPropertyValues().add(DECLARATION_ORDER_PROPERTY, order);
    //设置returning属性
    if (adviceElement.hasAttribute(RETURNING)) {
        adviceDefinition.getPropertyValues().add(
                RETURNING_PROPERTY, adviceElement.getAttribute(RETURNING));
    }
    //设置throwing属性
    if (adviceElement.hasAttribute(THROWING)) {
        adviceDefinition.getPropertyValues().add(
                THROWING_PROPERTY, adviceElement.getAttribute(THROWING));
    }
    //设置arg-names属性
    if (adviceElement.hasAttribute(ARG_NAMES)) {
        adviceDefinition.getPropertyValues().add(
                ARG_NAMES_PROPERTY, adviceElement.getAttribute(ARG_NAMES));
    }

    //下面的逻辑是通过构造函数初始化Advice类
    ConstructorArgumentValues cav = adviceDefinition.getConstructorArgumentValues();
    //构造函数第一个参数,advice对应aspect中的Method方法
    cav.addIndexedArgumentValue(METHOD_INDEX, methodDef);

    //  构造函数的第二个方法,配置的切面,支持pointcut-ref和pointcut
    //  配置advice的pointcut逻辑和解析pointcut标签一致
    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对象
    cav.addIndexedArgumentValue(ASPECT_INSTANCE_FACTORY_INDEX, aspectFactoryDef);

    return adviceDefinition;
}

逻辑还是一顿疯狂的属性配置,在我们简单使用的背后,spring做了这么多事情,真是感动。

到这里所有的配置都解析完成了,由于没有看到配置lazyinit,所以在创建代理的时候,这些advisor BeanDefinition会被初始化成对象放入BeanFactory中,接下来就讲解这些adivisor如何生效

AspectJAwareAdvisorAutoProxyCreator对Adivisor的处理

AspectJAwareAdvisorAutoProxyCreator继承AbstractAdvisorAutoProxyCreator,主要重载了AspectJAwareAdvisorAutoProxyCreator的sortAdvisors,extendAdvisors,shouldSkip方法

关于AbstractAdvisorAutoProxyCreator介绍可以看我之前的文章

我们分别来看下这三个方法做了什么事情

shouldSkip

protected boolean shouldSkip(Class<?> beanClass, String beanName) {
    // TODO: Consider optimization by caching the list of the aspect names
    List<Advisor> candidateAdvisors = findCandidateAdvisors();
    for (Advisor advisor : candidateAdvisors) {
        if (advisor instanceof AspectJPointcutAdvisor) {
            //用于跳过Aspect类,Aspect类的方法不需要被切
            if (((AbstractAspectJAdvice) advisor.getAdvice()).getAspectName().equals(beanName)) {
                return true;
            }
        }
    }
    return super.shouldSkip(beanClass, beanName);
}

这个方法用于过滤哪些bean不需要生成代理,在上面的逻辑排除了Aspect配置类

extendAdvisors

protected void extendAdvisors(List<Advisor> candidateAdvisors) {
    AspectJProxyUtils.makeAdvisorChainAspectJCapableIfNecessary(candidateAdvisors);
}

public static boolean makeAdvisorChainAspectJCapableIfNecessary(List<Advisor> advisors) {
    // Don't add advisors to an empty list; may indicate that proxying is just not required
    if (!advisors.isEmpty()) {
        boolean foundAspectJAdvice = false;
        for (Advisor advisor : advisors) {
            // Be careful not to get the Advice without a guard, as
            // this might eagerly instantiate a non-singleton AspectJ aspect
            // 判断advisors中是否存在AspectJ类型的Adivisor
            if (isAspectJAdvice(advisor)) {
                foundAspectJAdvice = true;
            }
        }
        //如果存在AspectJ的Aop配置,会在advisors数组头插入ExposeInvocationInterceptor
        if (foundAspectJAdvice && !advisors.contains(ExposeInvocationInterceptor.ADVISOR)) {
            advisors.add(0, ExposeInvocationInterceptor.ADVISOR);
            return true;
        }
    }
    return false;
}

extendAdvisors用来对得到adivisor进行扩展,这边会判断当前的Aop配置中是否存在AspectJ类型的配置,判断逻辑如下

private static boolean isAspectJAdvice(Advisor advisor) {
        return (advisor instanceof InstantiationModelAwarePointcutAdvisor ||
                advisor.getAdvice() instanceof AbstractAspectJAdvice ||
                (advisor instanceof PointcutAdvisor &&
                         ((PointcutAdvisor) advisor).getPointcut() instanceof AspectJExpressionPointcut));
    }

如果存在的话,会在adivisor数组加入ExposeInvocationInterceptor.ADVISOR,
同时ExposeInvocationInterceptor的优先级order是最高的

@Override
    public int getOrder() {
        return PriorityOrdered.HIGHEST_PRECEDENCE + 1;
    }

也就是拦截器链第一位会执行
注意一点,优先级order不代表数字最大,因为优先级最高,第一个被执行,那么对应排序要在第一位,所以数字需要越小越好,所以 PriorityOrdered.HIGHEST_PRECEDENCE对应

int HIGHEST_PRECEDENCE = Integer.MIN_VALUE;

ExposeInvocationInterceptor.ADVISOR对应的逻辑
这个类的invoke逻辑如下

@Override
public Object invoke(MethodInvocation mi) throws Throwable {
    MethodInvocation oldInvocation = invocation.get();
    invocation.set(mi);
    try {
        return mi.proceed();
    }
    finally {
        invocation.set(oldInvocation);
    }
}

其中invocation是ThreadLocal类型,这个adivisor的具体作用是可以让其他的aspectj类型的adivisor可以获取到当前的调用链路,因为adivisor的advice全是用代理生成的,只能通过JointPoint来获取调用链路

sortAdvisors

sortAdvisors会在extendAdvisors后执行

protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {
    List<Advisor> candidateAdvisors = findCandidateAdvisors();
    List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
    extendAdvisors(eligibleAdvisors);
    if (!eligibleAdvisors.isEmpty()) {
        eligibleAdvisors = sortAdvisors(eligibleAdvisors);
    }
    return eligibleAdvisors;
}

用来对Advisor进行排序,生成拦截器链,排在前面的会先调用

protected List<Advisor> sortAdvisors(List<Advisor> advisors) {
    List<PartiallyComparableAdvisorHolder> partiallyComparableAdvisors =
            new ArrayList<PartiallyComparableAdvisorHolder>(advisors.size());
    for (Advisor element : advisors) {
        partiallyComparableAdvisors.add(
                new PartiallyComparableAdvisorHolder(element, DEFAULT_PRECEDENCE_COMPARATOR));
    }
    List<PartiallyComparableAdvisorHolder> sorted =
            PartialOrder.sort(partiallyComparableAdvisors);
    if (sorted != null) {
        List<Advisor> result = new ArrayList<Advisor>(advisors.size());
        for (PartiallyComparableAdvisorHolder pcAdvisor : sorted) {
            result.add(pcAdvisor.getAdvisor());
        }
        return result;
    }
    else {
        return super.sortAdvisors(advisors);
    }
}

会通过PartiallyComparableAdvisorHolder包装Advisor,然后提供DEFAULT_PRECEDENCE_COMPARATOR的对比器

private static final Comparator<Advisor> DEFAULT_PRECEDENCE_COMPARATOR = new AspectJPrecedenceComparator();

通过这个对比器进行排序,排序好之后,再把advisor提取出来返回
内部代码不分析了,直接说下排序的算法

简单一句话,after类型的advice order越大优先级越高,其他的是order越小,优先级越高

最后

希望大家关注下我的公众号,我保证自己每天都能更新(有点难),为了我的粉丝哈


image
上一篇 下一篇

猜你喜欢

热点阅读