美文网首页Spring相关时序图系列
Spring AOP(4)再解

Spring AOP(4)再解

作者: 涣涣虚心0215 | 来源:发表于2021-01-06 18:38 被阅读0次

    <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

    相关文章

      网友评论

        本文标题:Spring AOP(4)再解

        本文链接:https://www.haomeiwen.com/subject/fnaboktx.html