今天看啥  ›  专栏  ›  涣涣虚心0215

Spring AOP(4)再解<aop:advisor>与<aop:aspect>

涣涣虚心0215  · 简书  ·  · 2021-01-06 18:38

<aop:advisor>:

 <aop:config>
    <aop:pointcut id="pointCut" expression="execution(* com.gary.spring.Student.*(..)) "/>
    <aop:advisor advice-ref="adviceHandler" pointcut-ref="pointCut"/>
</aop:config>

<aop:aspect>:

<aop:config>
    <aop:aspect id="aspect" ref="adviceHandler">
        <aop:pointcut id="pointCut" expression="execution(* com.gary.spring.Student.*(..)) "/>
        <aop:around method="doAround"  pointcut-ref="pointCut"/>
    </aop:aspect>
</aop:config>
1. 从配置文件上看

<aop:advisor>直接通过advice-ref和pointcut-ref指向advice和point。
<aop:aspect>需要在内部定义不同的advice类型,比如<aop:around>(注意<aop:pointcut>也可写到<aop:aspect>外部)

aspect
2. 从代码编写上看

这部分主要是Advice的编写
因为<aop:aspect>内部指定了Advice的类型,所以adviceHandler的实现类不需要实现任何借口,直接定义方法就行。

public class AdviceHandler  {
    public Object doAround(ProceedingJoinPoint pjp) throws Throwable {
        System.out.println("-----doAround().invoke-----");
        //调用核心逻辑
        Object retVal = pjp.proceed();
        System.out.println("-----End of doAround()------");
        return retVal;
    }
}

而<aop:advisor>对应的Advice实现就需要实现Advice接口,比如MethodBeforeAdvice。

public class AdviceHandler implements MethodBeforeAdvice, AfterReturningAdvice {
    @Override
    public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
        System.out.println(" 此处可以做类似于Before Advice的事情");
    }
    @Override
    public void before(Method method, Object[] args, Object target) throws Throwable {
        System.out.println(" 此处可以做类似于After Advice的事情");
    }
}
3. 从Spring解析过程来看

Spring AOP(3) 里面已经针对<aop:aspect>的实现做了粗略代码分析,这里就再好好分析一下。
核心代码就是parseCustomElement --> AopNamespaceHandler --> 加载ConfigBeanDefinitionParser --> parse()

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

    //核心代码,注册org.springframework.aop.config.internalAutoProxyCreator这个BeanDefinition,
    //    实例是AspectJAwareAdvisorAutoProxyCreator
    configureAutoProxyCreator(parserContext, element);

    List<Element> childElts = DomUtils.getChildElements(element);
    for (Element elt: childElts) {
        String localName = parserContext.getDelegate().getLocalName(elt);
        //解析PointCut
        if (POINTCUT.equals(localName)) {
            parsePointcut(elt, parserContext);
        }
        //解析Advisor
        else if (ADVISOR.equals(localName)) {
            parseAdvisor(elt, parserContext);
        }
        //解析Aspect
        else if (ASPECT.equals(localName)) {
            parseAspect(elt, parserContext);
        }
    }
    parserContext.popAndRegisterContainingComponent();
    return null;
}
(1) parsePointcut

针对<aop:pointcut>标签,解析创建并注册AspectJExpressionPointcut类型的BeanDefinition到BeanFactory。
代码如下:

private AbstractBeanDefinition parsePointcut(Element pointcutElement, ParserContext parserContext) {
    //拿到PointCut的id
    String id = pointcutElement.getAttribute(ID);
    //拿到PointCut配置的expression
    String expression = pointcutElement.getAttribute(EXPRESSION);
    AbstractBeanDefinition pointcutDefinition = null;
    try {
        this.parseState.push(new PointcutEntry(id));
        //创建pointCut的BeanDefinition
        pointcutDefinition = createPointcutDefinition(expression);
        //给BeanDefinition设置source
        pointcutDefinition.setSource(parserContext.extractSource(pointcutElement));
        String pointcutBeanName = id;
        if (StringUtils.hasText(pointcutBeanName)) {
            //如果设置了pointCut的ID,就把ID作为beanName,注册该BeanDefinition
            parserContext.getRegistry().registerBeanDefinition(pointcutBeanName, pointcutDefinition);
        }
        else {
            //如果没有ID,就需要生成一个beanName
            pointcutBeanName = parserContext.getReaderContext().registerWithGeneratedName(pointcutDefinition);
        }
        parserContext.registerComponent(
                new PointcutComponentDefinition(pointcutBeanName, pointcutDefinition, expression));
    }
    finally {
        this.parseState.pop();
    }
    return pointcutDefinition;
}
//创建AspectJExpressionPointcut类型的BeanDefinition,并且将expression作为property
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;
}

从下面截图就能看出,通过beanName "pointCut"就能拿到BeanDefinition,且有一个property "expression"。

<aop:pointcut id="pointCut" expression="execution(* com.gary.spring.Student.*(..)) "/>
PointCut
(2) parseAdvisor

创建 DefaultBeanFactoryPointcutAdvisor 类型的BeanDefinition,并设置pointCut和advice作为property。
注意这里如果是advice-ref或者point-ref那么通过RuntimeBeanNameReference包装,然后作为Advisor的property。
如果是pointCut,那么就直接创建pointCut的BeanDefinition,然后作为Advisor的property。
这里的不同点,在populateBean()的时候,会有区别。

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

    try {
        this.parseState.push(new AdvisorEntry(id));
        String advisorBeanName = id;
        if (StringUtils.hasText(advisorBeanName)) {
            //根据advisor的id作为beanName注册DefaultBeanFactoryPointcutAdvisor类型的BeanDefinition
            parserContext.getRegistry().registerBeanDefinition(advisorBeanName, advisorDef);
        }
        else {
            //如果没有ID,就生成一个beanName
            advisorBeanName = parserContext.getReaderContext().registerWithGeneratedName(advisorDef);
        }
        //拿到pointCut的BeanDefinition或者pointCut-ref的reference
        Object pointcut = parsePointcutProperty(advisorElement, parserContext);
        //如果是BeanDefinition,就直接将pointcut作为property加到Advisor的BeanDefinition
        if (pointcut instanceof BeanDefinition) {
            advisorDef.getPropertyValues().add(POINTCUT, pointcut);
            parserContext.registerComponent(
                    new AdvisorComponentDefinition(advisorBeanName, advisorDef, (BeanDefinition) pointcut));
        }
        //如果是reference,就组装为RuntimeBeanReference作为property加到Advisor的BeanDefinition
        else if (pointcut instanceof String) {
            advisorDef.getPropertyValues().add(POINTCUT, new RuntimeBeanReference((String) pointcut));
            parserContext.registerComponent(
                    new AdvisorComponentDefinition(advisorBeanName, advisorDef));
        }
    }
    finally {
        this.parseState.pop();
    }
}
//创建Advisor的BeanDefinition,并组装Advice
private AbstractBeanDefinition createAdvisorBeanDefinition(Element advisorElement, ParserContext parserContext) {
    //创建DefaultBeanFactoryPointcutAdvisor类型的BeanDefinition
    RootBeanDefinition advisorDefinition = new RootBeanDefinition(DefaultBeanFactoryPointcutAdvisor.class);
    advisorDefinition.setSource(parserContext.extractSource(advisorElement));
    //拿到advice-ref,即切面advice的引用
    String adviceRef = advisorElement.getAttribute(ADVICE_REF);
    if (!StringUtils.hasText(adviceRef)) {
        parserContext.getReaderContext().error(
                "'advice-ref' attribute contains empty value.", advisorElement, this.parseState.snapshot());
    }
    else {
        //将advice引用对应的bean作为property加入Advisor的BeanDefinition里
        advisorDefinition.getPropertyValues().add(
                ADVICE_BEAN_NAME, new RuntimeBeanNameReference(adviceRef));
    }
    //如果配置了order属性,同样将order加入Advisor的BeanDefinition
    if (advisorElement.hasAttribute(ORDER_PROPERTY)) {
        advisorDefinition.getPropertyValues().add(
                ORDER_PROPERTY, advisorElement.getAttribute(ORDER_PROPERTY));
    }

    return advisorDefinition;
}
//解析Advisor相关的pointCut属性
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,就跟parsePointcut逻辑一样,创建并注册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,就直接返回这个reference
    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;
    }
}

从下面图中可以看出DefaultBeanFactoryPointcutAdvisor还是比较直观好理解的,Advisor需要两个ref(advice和pointCut),作为property。

<aop:config>
    <aop:pointcut id="pointCut" expression="execution(* com.gary.spring.Student.*(..)) "/>
    <aop:advisor advice-ref="adviceHandler" pointcut-ref="pointCut"/>
</aop:config>
DefaultBeanFactoryPointcutAdvisor
(3) parseAspect

<aop:aspect>包含的item比较多,需要根据Advice的类型去创建BeanDefinition,以及PointCut的BeanDefinition,最后将Advice的BeanDefinition加入Advisor的BeanDefinition的构造函数中,那么在创建Advisor的时候,会通过autowireConstructor()来实例化Advice。

private void parseAspect(Element aspectElement, ParserContext parserContext) {
    //拿到appect的id
    String aspectId = aspectElement.getAttribute(ID);
    //拿到appect的name
    String aspectName = aspectElement.getAttribute(REF);

    try {
        this.parseState.push(new AspectEntry(aspectId, aspectName));
        //定义BeanDefinition的集合
        List<BeanDefinition> beanDefinitions = new ArrayList<>();
        //定义BeanReference的集合
        List<BeanReference> beanReferences = new ArrayList<>();
        //获取<aop:declare-parents>的配置
        List<Element> declareParents = DomUtils.getChildElementsByTagName(aspectElement, DECLARE_PARENTS);
        //创建DeclareParentsAdvisor类型的BeanDefinition,
        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.
        //开始解析Advice,即<aop:before>, <aop:after>, <aop:around>等标签
        NodeList nodeList = aspectElement.getChildNodes();
        boolean adviceFoundAlready = false;
        for (int i = 0; i < nodeList.getLength(); i++) {
            Node node = nodeList.item(i);
            //判断是不是before, after, around, after-returning, after-throwing
            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));
                }
                //如果找到任何一个标签,就开始创建Advice的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);

        List<Element> pointcuts = DomUtils.getChildElementsByTagName(aspectElement, POINTCUT);
        //调用parsePointcut解析<aop:pointcut>,创建AspectJExpressionPointcut BeanDefinition
        for (Element pointcutElement : pointcuts) {
            parsePointcut(pointcutElement, parserContext);
        }
        parserContext.popAndRegisterContainingComponent();
    }
    finally {
        this.parseState.pop();
    }
}
//<aop:around method="doAround" pointcut-ref="pointCut"/>
//根据这个配置解析method以及pointcut-ref
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
        //注册MethodLocatingFactoryBean的BeanDefinition,设置targetBeanName和methodName
        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
        //创建SimpleBeanFactoryAwareAspectInstanceFactory的BeanDefinition,设置aspectBeanName
        RootBeanDefinition aspectFactoryDef =
                new RootBeanDefinition(SimpleBeanFactoryAwareAspectInstanceFactory.class);
        aspectFactoryDef.getPropertyValues().add("aspectBeanName", aspectName);
        aspectFactoryDef.setSynthetic(true);
        // register the pointcut
        AbstractBeanDefinition adviceDef = createAdviceDefinition(
                adviceElement, parserContext, aspectName, order, methodDefinition, aspectFactoryDef,
                beanDefinitions, beanReferences);
        // configure the advisor
        // 上面创建玩Advice的BeanDefinition,接着创建AspectJPointcutAdvisor advisor的BeanDefinition
        RootBeanDefinition advisorDefinition = new RootBeanDefinition(AspectJPointcutAdvisor.class);
        advisorDefinition.setSource(parserContext.extractSource(adviceElement));
        // 将Advice的BeanDefinition,作为Advisor BeanDefinition的构造函数参数
        advisorDefinition.getConstructorArgumentValues().addGenericArgumentValue(adviceDef);
        if (aspectElement.hasAttribute(ORDER_PROPERTY)) {
            advisorDefinition.getPropertyValues().add(
                    ORDER_PROPERTY, aspectElement.getAttribute(ORDER_PROPERTY));
        }
        // register the final advisor
        parserContext.getReaderContext().registerWithGeneratedName(advisorDefinition);
        return advisorDefinition;
    }
    finally {
        this.parseState.pop();
    }
}
//创建AspectJAroundAdvice类型的BeanDefinition,并且将method-ref和pointcut-ref添加到该BeanDefinition的构造函数中
private AbstractBeanDefinition createAdviceDefinition(
        Element adviceElement, ParserContext parserContext, String aspectName, int order,
        RootBeanDefinition methodDef, RootBeanDefinition aspectFactoryDef,
        List<BeanDefinition> beanDefinitions, List<BeanReference> beanReferences) {

    //根据before, after, around, after-returning, after-throwing,不同的Advice类型,返回不同的Advice类
    //比如AspectJAroundAdvice, AspectJMethodBeforeAdvice
    RootBeanDefinition adviceDefinition = new RootBeanDefinition(getAdviceClass(adviceElement, parserContext));
    adviceDefinition.setSource(parserContext.extractSource(adviceElement));
    //设置Advice BeanDefinition的aspectName以及order属性
    adviceDefinition.getPropertyValues().add(ASPECT_NAME_PROPERTY, aspectName);
    adviceDefinition.getPropertyValues().add(DECLARATION_ORDER_PROPERTY, order);
    //如果存在returning, throwing, arg-names等attribute,添加到Advice BeanDefinition的属性上
    if (adviceElement.hasAttribute(RETURNING)) {
        adviceDefinition.getPropertyValues().add(
                RETURNING_PROPERTY, adviceElement.getAttribute(RETURNING));
    }
    if (adviceElement.hasAttribute(THROWING)) {
        adviceDefinition.getPropertyValues().add(
                THROWING_PROPERTY, adviceElement.getAttribute(THROWING));
    }
    if (adviceElement.hasAttribute(ARG_NAMES)) {
        adviceDefinition.getPropertyValues().add(
                ARG_NAMES_PROPERTY, adviceElement.getAttribute(ARG_NAMES));
    }

    ConstructorArgumentValues cav = adviceDefinition.getConstructorArgumentValues();
    cav.addIndexedArgumentValue(METHOD_INDEX, methodDef);
    //解析pointCut的属性,与parseAdvisor里面调用的方法一样
    //区别就是这里不仅仅初始化PointCut的BeanDefinition,还会将methodDef, pointcut, aspectFactoryDef放入Advice BeanDefinition的构造函数
    Object pointcut = parsePointcutProperty(adviceElement, parserContext);
    //如果pointcut是BeanDefinition类型就直接设置到Advice BeanDefinition的构造函数
    if (pointcut instanceof BeanDefinition) {
        cav.addIndexedArgumentValue(POINTCUT_INDEX, pointcut);
        beanDefinitions.add((BeanDefinition) pointcut);
    }
    //如果pointcut是String类型,即pointcut-ref,就封装RuntimeBeanReference设置到Advice BeanDefinition的构造函数
    else if (pointcut instanceof String) {
        RuntimeBeanReference pointcutRef = new RuntimeBeanReference((String) pointcut);
        cav.addIndexedArgumentValue(POINTCUT_INDEX, pointcutRef);
        beanReferences.add(pointcutRef);
    }
    cav.addIndexedArgumentValue(ASPECT_INSTANCE_FACTORY_INDEX, aspectFactoryDef);
    return adviceDefinition;
}

AspectJPointcutAdvisor比DefaultBeanFactoryPointcutAdvisor复杂很多

<aop:aspect id="aspect" ref="adviceHandler">
        <aop:pointcut id="pointCut" expression="execution(* com.gary.spring.Student.*(..)) "/>
        <aop:around method="doAround"  pointcut-ref="pointCut"/>
</aop:aspect>

通过beanName "org.springframework.aop.aspectj.AspectJPointcutAdvisor#0"就能拿到BeanDefinition,且有一个构造函数 "AbstractAspectJAdvice"。

//构造函数,所以AspectJPointcutAdvisor需要通过构造函数注入Advice
public AspectJPointcutAdvisor(AbstractAspectJAdvice advice) {
    Assert.notNull(advice, "Advice must not be null");
    this.advice = advice;
    this.pointcut = advice.buildSafePointcut();
}
Aspect

再点进去查看AspectJAroundAdvice的BeanDefinition,它存在三个构造函数参数,和两个property。

AspectJAroundAdvice

AspectJAroundAdvice 的三个构造参数分别注入的是MethodLocationFactoryBean,PointCut,SimpleBeanFactoryAwareAspectInstanceFactory。

  • MethodLocationFactoryBean 有两个property:targetBeanName和methodName,表示通知类advice的通知方法。
    且它是一个FactoryBean,getObject()方法直接返回method,方便AspectJAroundAdvice拦截的时候通过method反射调用通知方法。
    @Override
    public void setBeanFactory(BeanFactory beanFactory) {
        if (!StringUtils.hasText(this.targetBeanName)) {
            throw new IllegalArgumentException("Property 'targetBeanName' is required");
        }
        if (!StringUtils.hasText(this.methodName)) {
            throw new IllegalArgumentException("Property 'methodName' is required");
        }
        //从BeanFactory中获取beanClass
        Class<?> beanClass = beanFactory.getType(this.targetBeanName);
        if (beanClass == null) {
            throw new IllegalArgumentException("Can't determine type of bean with name '" + this.targetBeanName + "'");
        }
        //通过反射拿到method
        this.method = BeanUtils.resolveSignature(this.methodName, beanClass);

        if (this.method == null) {
            throw new IllegalArgumentException("Unable to locate method [" + this.methodName +
                    "] on bean [" + this.targetBeanName + "]");
        }
    }
    //FactoryBean在实例化之后会调用getObject(),那么MethodLocationFactoryBean实例化最终返回的是method
    public Method getObject() throws Exception {
        return this.method;
    }
MethodLocationFactoryBean
  • pointCut
    因为本例中使用pointCut,所以这里pointCut是RuntimeBeanReference,在注入的时候会去注入pointCut对应的Bean。
pointCut
  • SimpleBeanFactoryAwareAspectInstanceFactory
    这是个工厂类,可以根据aspectBeanName去获取对应的bean。
    在本例中,adviceHandler是在AspectJAroundAdvice被invoke调用时,通过该Factory来实例化bean的。
    //AspectJAroundAdvice拦截器被调用
    protected Object invokeAdviceMethodWithGivenArgs(Object[] args) throws Throwable {
        Object[] actualArgs = args;
        if (this.aspectJAdviceMethod.getParameterCount() == 0) {
            actualArgs = null;
        }
        try {
            ReflectionUtils.makeAccessible(this.aspectJAdviceMethod);
            // TODO AopUtils.invokeJoinpointUsingReflection
            return this.aspectJAdviceMethod.invoke(this.aspectInstanceFactory.getAspectInstance(), actualArgs);
        }
        catch (IllegalArgumentException ex) {
            throw new AopInvocationException("Mismatch on arguments to advice method [" +
                    this.aspectJAdviceMethod + "]; pointcut expression [" +
                    this.pointcut.getPointcutExpression() + "]", ex);
        }
        catch (InvocationTargetException ex) {
            throw ex.getTargetException();
        }
    }
    public Object getAspectInstance() {
        Assert.state(this.beanFactory != null, "No BeanFactory set");
        Assert.state(this.aspectBeanName != null, "No 'aspectBeanName' set");
        return this.beanFactory.getBean(this.aspectBeanName);
    }
SimpleBeanFactoryAwareAspectInstanceFactory



原文地址:访问原文地址
快照地址: 访问文章快照