Spring boot @Aspect

  • 使用场景
  • 列子1 (演示基本过程
  • 切点表达式
    • 切点复合运算
    • 切点匹配方法
  • 通知注解
  • 切面类执行顺序

使用场景

  • 常见用于记录日志, 异常集中处理, 权限验证以及 Web参数有效验证等等

列子1 (演示基本过程


@Aspect
@Component
public class TestAspect {/*** 声明一个切入点, 命名 pointcut1* */@Pointcut("execution(public java.util.Map com.example.demo.controller.TestService.getMap(String, Integer))")private void pointcut1() {}/*** 锁定的切点方法之前执行* JoinPoint 获取连接点信息 *  -   Object[] getArgs()          获取连接点方法运行时的入参列表*    -   Signature getSignature()    获取连接点的方法签名对象*   -   Object getTarget()          获取连接点所在的目标对象*   -   Object getThis()            获取代理对象* */@Before("pointcut1()")public void aspect1(JoinPoint joinPoint) {System.out.println("TestAspect -> @Before 方法名称:" + joinPoint.getSignature().getName() + ", 参数:" + Arrays.asList(joinPoint.getArgs()));}/*** 锁定的切点方法之后执行* */@After("pointcut1()")public void aspect2() {System.out.println("TestAspect -> @After");}/*** 锁定的切点方法返回后执行* */@AfterReturning(pointcut = "pointcut1()", returning="result")public void aspect3(Object result){System.out.println("TestAspect -> @AfterReturning 返回值:" + result);}}@Service
public class TestService {public Map<String, Object> getMap(String name, Integer age) {final Map<String, Object> result = new HashMap<>(2);result.put("name", name);result.put("age", age);System.out.println("TestService -> getMap 函数体内输出:" + result);return result;}}# 测试地址 http://127.0.0.1:8080/aspectTest
@RestController
public class AspectController {@Autowiredprivate TestService testService;@GetMapping(value = "/aspectTest")public Map<String, Object> aspectTest(@RequestParam(value="name", required=false, defaultValue="大爷") String name,@RequestParam(value="age", required=false, defaultValue="35") Integer age) {System.out.println("AspectController -> aspectTest");return testService.getMap(name, age);}}# 输出
AspectController -> aspectTest
TestAspect -> @Before 方法名称:getMap, 参数:[大爷, 35]
TestService -> getMap 函数体内输出:{name=大爷, age=35}
TestAspect -> @After
TestAspect -> @AfterReturning 返回值:{name=大爷, age=35}

切点表达式

  1. ..两个点表明多个, *代表一个
  2. 其中权限修饰符是可选, 当不写时不能用*代替, 因此第一个*代表返回类型不限
  3. 第二个*表示指定包下所有类
  4. 第三个*表示指定类下所有方法
  5. (..)两个点表示指定方法的参数不限

@Pointcut(execution(* com..demo.controller.*.*(..)))

切点复合运算

  • 切点表达式可以加运算符 与&&, 或||, 非! 做复合运算

@Before(value="execution(* com.example.demo.controller.TestService.getMap(..)) && args(name, age, ..)")

切点匹配方法

  • execution: 用于匹配方法的执行
  • within: 用于匹配指定类内的方法的执行
  • args: 用于指定匹配方法的参数类型
  • target: 用于匹配容器内的类的对象执行方法, 不包括引入接口
  • this: 用于匹配容器内的类的对象执行方法, 包括引入接口

注: target和 this两种方法表达式必须全限定名到类名, 不支持*通配符

通知注解

  • @Before: 前置通知, 在方法执行之前执行
  • @After: 后置通知, 在方法执行之后执行
  • @AfterRunning: 返回通知, 在方法返回结果之后执行

@AfterReturning(pointcut = "pointcut1()", returning="result")
public void aspect3(JoinPoint joinPoint, Object result){System.out.println("TestAspect1 -> @AfterReturning 返回值:" + result);
}# 执行过程
Request -> @Before -> Method -> @After -> @AfterReturning    
  • @AfterThrowing: 异常通知, 在方法抛出异常之后执行, 意味着跳过返回通知

/**
* 指定方法内抛出异常时才会被通知
* 属性 throwing上设置异常类 Throwable将会捕获任何错误和异常, 或按需设置指定异常类
*/
@AfterThrowing(pointcut = "pointcut1()", throwing="ex")
public void aspect4(JoinPoint joinPoint, TestException ex) {System.out.println("TestAspect1 -> @AfterThrowing 异常:" + ex.getMessage());
}# 执行过程
Request -> @Before -> Method -> @After -> @AfterThrowing
  • @Around: 环绕通知, 围绕着方法执行

/**
* ProceedingJoinPoint继承于 JoinPoint接口, 并多了两个方法
*   -   Object proceed() throws Throwable       通过反射执行目标对象连接点处的方法
*   -   Object proceed(Object[] var1) throws Throwable  通过入参替换原参, 通过反射执行目标对象连接点处的方法
*/
@Around("pointcut1()")
public Object aspect5(ProceedingJoinPoint pjp) throws Throwable {System.out.println("TestAspect1 -> @Around start");Object[] args = pjp.getArgs();for (Object arg : args) {System.out.println("TestAspect1 -> @Around 参数:" + arg); // 输出指定方法参数}long startTime = System.currentTimeMillis();Object object = pjp.proceed(); // 调用 proceed后指定方法会被执行long endTime = System.currentTimeMillis();System.out.println("TestAspect1 -> @Around " + (endTime - startTime) + " ms");return object;
}# 输出
AspectController -> aspectTest
TestAspect1 -> @Around start
TestAspect1 -> @Around 参数:大爷
TestAspect1 -> @Around 参数:35
TestAspect1 -> @Before
TestService -> getMap 函数体内输出:{name=大爷, age=35}
TestAspect1 -> @Around 0 ms
TestAspect1 -> @After
TestAspect1 -> @AfterReturning 返回值:{name=大爷, age=35}# 正常执行过程
Request -> @Around -> @Before -> Method -> @Around -> @After -> @AfterReturning
# 异常执行过程
Request -> @Around -> @Before -> Method -> @Around -> @After -> @AfterThrowing

切面类执行顺序

  • 通过 @Order注解设置, 数越小越靠前

@Aspect
@Component
@Order(3)
public class TestAspect1 {}

如果您觉得有帮助,欢迎点赞哦 ~ 谢谢!!

Spring @Aspect注解相关推荐

  1. Spring @Aspect简单使用

    一.AOP概念 在软件业,AOP为Aspect Oriented Programming的缩写,意为:面向切面编程,通过预编译方式和运行期间动态代理实现程序功能的统一维护的一种技术.AOP是OOP的延 ...

  2. 【spring】让spring的注解和xml配置文件变得优雅,最常用的注解

    其实,对注解的使用,应该是:先用xml,对某个注解足够了解够,用上这个注解,省去部分xml.循序渐进,既少了xml配置文件的配置,也不失代码的可读性和对代码的理解. MD,刚刚服务器挂了,害我又写一遍 ...

  3. 第五章 Spring进阶-注解方式实现AOP(1)

    <?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" /> 徒弟:师傅,我 ...

  4. Spring基于注解的AOP配置

    pom.xml <?xml version="1.0" encoding="UTF-8"?> <project xmlns="htt ...

  5. java中spring的注解_spring中的各种注解解析

    Spring中的注解大概可以分为两大类: 1)spring的bean容器相关的注解,或者说bean工厂相关的注解: 2)springmvc相关的注解. spring的bean容器相关的注解,先后有:@ ...

  6. Spring AOP注解方式实现

    简介 上文已经提到了Spring AOP的概念以及简单的静态代理.动态代理简单示例,链接地址:https://www.cnblogs.com/chenzhaoren/p/9959596.html 本文 ...

  7. Java 必须掌握的 12 种 Spring 常用注解

    转载自  Java 必须掌握的 12 种 Spring 常用注解 1.声明bean的注解 @Component 组件,没有明确的角色 @Service 在业务逻辑层使用(service层) @Repo ...

  8. Spring AOP注解为什么失效?90%Java程序员不知道

    转载自 Spring AOP注解为什么失效?90%Java程序员不知道 使用Spring Aop注解的时候,如@Transactional, @Cacheable等注解一般需要在类方法第一个入口的地方 ...

  9. java spring aop 注解包_Spring AOP 注解配置实例

    Spring AOP注解例子 一:导入相关jar包. 首先导入Spring的相关包(这里就不多说了,我这里是3.2.4版本的) 然后导入AOP注解的相关包(不是spring的包)aspectjrt-1 ...

  10. java spring boot 注解验证_如何理解Java原生注解和Spring 各种注解?

    作者:digdeep .cnblogs.com/digdeep/p/4525567.html 导引 Spring中的注解大概可以分为两大类: spring的bean容器相关的注解,或者说bean工厂相 ...

最新文章

  1. 使用多个推理芯片需要仔细规划
  2. 聊天机器人之语料准备
  3. R语言plotly可视化:plotly可视化累积cumulative直方图(Cumulative Histogram)
  4. golang中的反射
  5. 零元学Expression Blend 4 - Chapter 38 看如何使用Clip修出想要的完美曲线(下)
  6. 看完这篇还不清楚Netty的内存管理,那我就哭了!
  7. java继续_Java中消除实现继续和面向接口编程
  8. IPv4地址在mysql的存储
  9. python3重写new方法_Python 3.8 新功能一览
  10. Hadoop之crontab与ntpd
  11. E: 无法打开锁文件 /var/lib/dpkg/lock-frontend - open (2: 没有那个文件或目录)
  12. scala和java数据类型转换
  13. 简单的C语言程序介绍(重点理解),超详细基础代码解析
  14. 如何“复活”一个人,这里有一份最全的技术路线图谱丨钛媒体深度
  15. 【在linux系统中使用绘王HC16数位板绘画】
  16. 解决Ubuntu19.04下网易云音乐打不开的问题
  17. 联想小新air pro 13的 win10和ubuntu17.10双系统安装,彻底解决找不到磁盘问题。
  18. 关于几何学发展的三阶段
  19. 疫情信息管理系统(附源代码及数据库)
  20. nth-child 实用技巧

热门文章

  1. 如何选择合适焦距工业相机镜头
  2. mongodb导入JSON数据报错:Document is larger than the maximum size
  3. 页面无法自动播放音频的解决方案
  4. git中rejected的解决方法
  5. 【七夕节特刊】开源世界里的爱情保卫战
  6. TCP序列号(Sequence Number)和确认号(Acknowledgment Number)
  7. noob之MySQL基本查询
  8. linux 路由配置工具下载,Linux/Openwrt路由安装配置UPNP服务提高迅雷下载速度
  9. php展厅控制系统,展厅中控系统
  10. 利用ckplayer浏览器在线播放视频并获取视频预览图方法