Spring(十九):Spring AOP(三):切面的优先级

背景:

1)指定切面优先级示例:有的时候需要对一个方法指定多个切面,而这多个切面有时又需要按照不同顺序执行,因此,切面执行优先级别指定功能就变得很实用。

2)重复使用切入点表达式:上一篇文章中,定义前置、后置、返回、异常通知的切入点表达式时,都使用了同一个;而且本章节新加入的验证切面ValidateAspect类,也使用同一个切入点表达式,怎么让他们重用呢?

指定切面优先级示例:

比如在算术计算器执行计算之前进行数据验证,验证完事之后才让执行日志输出。

新建spring aop项目参考:《Spring(十八):Spring AOP(二):通知(前置、后置、返回、异常、环绕)

添加验证切面类:

package com.dx.spring.beans.aop;

import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;

@Component
@Aspect
public class ValidateAspect {
    @Before("execution(public int com.dx.spring.beans.aop.IArithmeticCalculator.*(..))")
    public void beforeMethod() {
        System.out.println("validate...");
    }
}

除了验证切面,还包含日志切面:

package com.dx.spring.beans.aop;

import java.util.List;
import java.util.Arrays;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;

//把这个类声明为一个切面:需要把该类放入到IOC容器中、再声明为一个切面。
@Aspect
@Component
public class LoggingAspect {
    // 声明该方法为一个前置通知:在目标方法开始之前执行
    @Before("execution(public int com.dx.spring.beans.aop.IArithmeticCalculator.*(int, int))")
    public void beforeMethod(JoinPoint joinpoint) {
        String methodName = joinpoint.getSignature().getName();
        List<Object> args = Arrays.asList(joinpoint.getArgs());
        System.out.println("before method " + methodName + " with " + args);
    }

    // 声明该方法为一个后置通知:在目标方法结束之后执行(无论方法是否抛出异常)。
    // 但是因为当方法抛出异常时,不能返回值为null,因此这里无法获取到异常值。
    @After(value = "execution(public int com.dx.spring.beans.aop.IArithmeticCalculator.*(int,int))")
    public void afterMethod(JoinPoint joinpoint) {
        String methodName = joinpoint.getSignature().getName();
        List<Object> args = Arrays.asList(joinpoint.getArgs());
        System.out.println("after method " + methodName);
    }

    /**
     * 声明该方法为一个返回通知:在目标方法返回结果时后执行(当方法抛出异常时,无法执行)。 但是因为当方法抛出异常时,类似代码 {@code
     * try <br/>
     * { <br/>
     * // before 前置通知 <br/>
     * // do action method <br/>
     * // after returning 返回通知,可以访问到方法的返回值 <br/>
     * } catch(Exception e){ e.printStackTrace(); // after throwing
     * 异常通知,可以访问到方法出现的异常 } // after 后置通知,因为方法可以抛出异常,所以访问不到方法的返回值 }
     */
    @AfterReturning(value = "execution(public int com.dx.spring.beans.aop.IArithmeticCalculator.*(int,int))", returning = "result")
    public void afterReturningMethod(JoinPoint joinpoint, Object result) {
        String methodName = joinpoint.getSignature().getName();
        List<Object> args = Arrays.asList(joinpoint.getArgs());
        System.out.println(
                "after method " + methodName + " with returning " + (result == null ? "NULL" : result.toString()));
    }

    /**
     * 定义一个异常通知函数: 只有在方法跑吹异常时,该方法才会执行,而且可以接受异常对象。
     */
    @AfterThrowing(value = "execution(public int com.dx.spring.beans.aop.IArithmeticCalculator.*(int,int))", throwing = "ex")
    public void afterThrowingMethod(JoinPoint joinpoint, Exception ex) {
        String methodName = joinpoint.getSignature().getName();
        List<Object> args = Arrays.asList(joinpoint.getArgs());
        System.out.println(
                "after method " + methodName + " occurs exception: " + (ex == null ? "NULL" : ex.getMessage()));
    }

//    @Around(value = "execution(public int com.dx.spring.beans.aop.IArithmeticCalculator.*(int, int))")
//    public Object aroundMethod(ProceedingJoinPoint pJoinPoint) throws Exception {
//        String methodName = pJoinPoint.getSignature().getName();
//        List<Object> args = Arrays.asList(pJoinPoint.getArgs());
//
//        Object result = null;
//        try {
//            // 前置通知
//            System.out.println("before method " + methodName + " with " + args);
//            // 执行目标方法
//            result = pJoinPoint.proceed();
//            // 返回通知
//            System.out.println("after method " + methodName + " returning " + result);
//        } catch (Throwable ex) {
//            // 异常通知
//            System.out.println("after method " + methodName + " occurs exception: " + ex.getMessage());
//            throw new Exception(ex);
//        }
//        // 后置通知
//        System.out.println("after method " + methodName);
//        return result;
//    }
}

默认打印结果:

按照实际业务需求来讲,更希望是先执行验证切面,才执行日志切面,那么,可以通过设置切面优先级别来设置:

修改ValidateAspect.java添加注解@Order(1)

@Order(value=1)
@Component
@Aspect
public class ValidateAspect {
    @Before("execution(public int com.dx.spring.beans.aop.IArithmeticCalculator.*(..))")
    public void beforeMethod() {
        System.out.println("validate...");
    }
}

修改LoggingAspect.java添加注解@Order(2)

@Order(value=2)
@Aspect
@Component
public class LoggingAspect {
    //代码
}

此时执行结果为:

重使用切入点表达式:

上一篇文章中,定义前置、后置、返回、异常通知的切入点表达式时,都使用了同一个;而且本章节新加入的验证切面ValidateAspect类,也使用同一个切入点表达式,怎么让他们重用呢?

第一步:修改LoggingAspect切面类,添加@Pointcut注解的方法declareAspectJoinPointExpression():

//把这个类声明为一个切面:需要把该类放入到IOC容器中、再声明为一个切面。
@Order(value=2)
@Aspect
@Component
public class LoggingAspect {
    @Pointcut("execution(public int com.dx.spring.beans.aop.IArithmeticCalculator.*(..))")
    public void declareAspectJoinPointExpression(){

    }
        //...
}

第二步:修改LoggingAspect切面类,把前置、后置、返回、异常、环绕通知方法的切入点表达式替换为“declareAspectJoinPointExpression()”

以前置通知方法为例:

//把这个类声明为一个切面:需要把该类放入到IOC容器中、再声明为一个切面。
@Order(value=2)
@Aspect
@Component
public class LoggingAspect {
    @Pointcut("execution(public int com.dx.spring.beans.aop.IArithmeticCalculator.*(..))")
    public void declareAspectJoinPointExpression(){

    }
    // 声明该方法为一个前置通知:在目标方法开始之前执行
    @Before("declareAspectJoinPointExpression()")
    public void beforeMethod(JoinPoint joinpoint) {
        String methodName = joinpoint.getSignature().getName();
        List<Object> args = Arrays.asList(joinpoint.getArgs());
        System.out.println("before method " + methodName + " with " + args);
    }
        //...
}

第三步:修改验证切面类ValidateAspect.java:

@Order(value=1)
@Component
@Aspect
public class ValidateAspect {
    @Before("com.dx.spring.beans.aop.LoggingAspect.declareAspectJoinPointExpression()")
    public void beforeMethod() {
        System.out.println("validate...");
    }
}

备注:如果在同一个包下,可以不指定包的路径。

第四步:验证

原文地址:https://www.cnblogs.com/yy3b2007com/p/9131005.html

时间: 2024-10-08 19:34:28

Spring(十九):Spring AOP(三):切面的优先级的相关文章

spring-第十九篇AOP面向切面编程之增强处理的优先级

1.从我们第十七篇举例了不同类型的增强处理. spring AOP采用和AspectJ一样的优先顺序来织入增强处理:在“进入”连接点时,具有最高优先级的增强处理将先被织入(在给定的两个Before增强处理,优先级高的将会先被执行),在“退出”连接点时,具有最高优先级的增强处理会最后被织入(在给定的两个After增强处理中,优先级高的那个会后执行). 当不同切面里的两个增强处理需要在同一个连接点被织入时,spring AOP将以随机的顺序来织入这两个增强处理.如果用户应用需要指定不同切面类里的增强

spring学习九 spring aop详解

本文来自于:https://www.cnblogs.com/jingzhishen/p/4980551.html AOP(Aspect-Oriented Programming,面向方面编程),可以说是OOP(Object-Oriented Programing,面向对象编程)的补充和完善.OOP引入封装.继承和多态性等概念来建立一种对象层次结构,用以模拟公共行为的一个集合.当我们需 要为分散的对象引入公共行为的时候,OOP则显得无能为力.也就是说,OOP允许你定义从上到下的关系,但并不适合定义

Spring学习(十九)----- Spring与WEB容器整合

首先可以肯定的是,加载顺序与它们在 web.xml 文件中的先后顺序无关.即不会因为 filter 写在 listener 的前面而会先加载 filter.最终得出的结论是:listener -> filter -> servlet 同时还存在着这样一种配置节:context-param,它用于向 ServletContext 提供键值对,即应用程序上下文信息.我们的 listener, filter 等在初始化时会用到这些上下文中的信息,那么 context-param 配置节是不是应该写在

hiho一下 第二十九周 最小生成树三&#183;堆优化的Prim算法【14年寒假弄了好长时间没搞懂的prim优化:prim算法+堆优化 】

题目1 : 最小生成树三·堆优化的Prim算法 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 回到两个星期之前,在成功的使用Kruscal算法解决了问题之后,小Ho产生了一个疑问,究竟这样的算法在稀疏图上比Prim优化之处在哪里呢? 提示:没有无缘无故的优化! 输入 每个测试点(输入文件)有且仅有一组测试数据. 在一组测试数据中: 第1行为2个整数N.M,表示小Hi拥有的城市数量和小Hi筛选出路线的条数. 接下来的M行,每行描述一条路线,其中第i行为3个整数N1_

第十九课(三)

文章 ピーターパンは永遠の若さの代名詞だ 寄せる 濁る にごる 濁っている苦情が水道局に寄せられ.浄水器をつけたり.一度.沸かしてから(わかす)飲んだりする人が多かった -に苦情を寄せる 提意见 -つつある 変わりつつある 物価が上がりつつある 都庁 とちょう -に-とある 在什么地方有什么 この「東京水」の販売は東京都水道局が進めている「安全で美味しい水プロジェクト」キャンペーンの一つだ 並びに 并列两个同类名词 キャンペーンでは貯水池ならびに河川(かせん)の水質管理.浄水処理施設の改善など.

Linux学习(二十九)iptables(三)nat表的应用

需求 A机器可以访问外网,B机器和A机器处于同一个内网,现在要让B机器通过A机器访问外网. 步骤 1.为虚拟机添加一块网卡. 如果没有区段名称的话,点击'LAN区段(S)...'按钮,新建一个. 2.ifconfig -a命令可以看到刚添加进来的尚未启用的网卡: [[email protected] ~]# ifconfig -a eth1 Link encap:Ethernet HWaddr 00:0C:29:AC:CC:56 inet addr:192.168.182.130 Bcast:1

详解Spring面向切面编程(AOP)三种实现

一.什么是AOP AOP(Aspect Oriented Programming),即面向切面编程,可以说是OOP(Object Oriented Programming,面向对象编程)的补充和完善.OOP引入封装.继承.多态等概念来建立一种对象层次结构,用于模拟公共行为的一个集合.不过OOP允许开发者定义纵向的关系,但并不适合定义横向的关系,例如日志功能.日志代码往往横向地散布在所有对象层次中,而与它对应的对象的核心功能毫无关系对于其他类型的代码,如安全性.异常处理和透明的持续性也都是如此,这

sprint.net(2) AOP面向切面编程,spring.net的环绕通知;Spring.net的AOP通知的四种类型

AOP 有点类似于我们MVC里面的Filter过滤器,例如在MVC里面,如果给一个Action上打一个标签,就可以在这个Action执行之前或者之后,额外的执行一个方法,这个就相当于是面向切面编程. 无侵入式的. (也就是在不改变原来的代码的情况下,来跳转到一个其他的方法,执行完毕后回到主方法..),但是spring.net的AOP更牛叉,只需要在xml里面配置,就可以了,不需要在方法上面打特性的标签,也不需要继承什么类(例如MVC的过滤器是继承了ActionFilterAttribute) 主

Spring(二):AOP(面向切面编程),Spring的JDBC模板类

1 AOP概述 1.2 什么是AOP 在软件业,AOP为Aspect Oriented Programmig的缩写,意为:面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术.AOP是OOP的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生范型.利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率. AOP解决了OOP遇到一些问题,采取横向抽取机制,取代了传统

Spring框架 AOP(三)

AOP理论概述 Aspect Oriented Programming 面向切面编程 业界 AOP 实际上 OOP (面向对象编程 ) 延伸 -- OOP编程语言. AOP设计思想 AOP采取横向抽取机制,取代了传统纵向继承体系重复性代码(性能监视.事务管理.安全检查.缓存) 横向抽取代码复用,基于代理技术,在不修改原有对象代码情况下,对原有对象方法功能进行增强! ---- AOP 思想 Spring框架如何实现AOP Spring1.2 版本开始 开始支持AOP技术 (传统Spring AOP