- SpringBoot 入门
- SpringBoot 基本原理
- SpringBoot 自定义配置
- SpringBoot 热部署配置
- SpringBoot 进行 Junit 测试
- SpringBoot 整合 MyBatis
- SpringBoot 事务配置
- SpringBoot 与 JSP 集成
- SpringBoot 项目的 WAR 部署方式
- SpringBoot 整合 WebSocket
- SpringBoot 中 MVC 解决日期转换配置
- SpringBoot 中 Jackson 的使用
- SpringBoot 聚合项目创建时 父工程不再是 spring boot starter parent 如何解决
- SpringBoot 使用 CORS 解决跨域问题
- SpringBoot 手动回滚事务
- SpringBoot 项目中 AOP 的配置
- SpringBoot 项目配置文件加密
- SpringBoot 配置文件读取
- 请求参数注解校验
- SpringApplication 源码分析
- SpringBoot 自动配置基本原理
- 自定义 SpringBoot starter
- SpringBoot 自动配置之条件注解
- SpringBoot SPI 机制
SpringBoot 项目中 AOP 的配置
一. 通知的分类
- 前置通知(Before):在切入点执行之前执行
- 正常返回通知(AfterReturning):只有切入点正常返回时才执行
- 异常返回通知(AfterThrowing):只有切入点抛出异常返回时才执行
- 返回通知(After):不管是正常返回还是异常返回都执行
- 环绕通知(Around):环绕通知
二. SpringBoot 配置
第一步:给项目加入 AOP 依赖
<!--引入 AOP 依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
注意:在完成了引入 AOP 依赖包后,不需要去做其他配置。AOP 的默认配置属性中,spring.aop.auto 属性默认是开启的,也就是说只要引入了 AOP 依赖后,默认已经增加了 @EnableAspectJAutoProxy,不需要在程序主类中增加 @EnableAspectJAutoProxy 来启用。
第二步:准备目标对象(被加强)
package com.example.demo.aop;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @desc: 核心业务模块
* @author: CSH
**/
@RestController
public class AopController {
@GetMapping("/test")
public void test(){
System.out.println("Hello World!");
}
}
第三步:定义通知类
定义切面类:在类上添加 @Aspect 和 @Component 注解即可将一个类定义为切面类。
@Aspect 注解 使之成为切面类
@Component 注解 把切面类加入到 IOC 容器中
package cn.tjd.springparametercheck.aspect;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;
/**
* @Auther: TJD
* @Date: 2020-03-28
* @DESCRIPTION:
**/
@Aspect
@Component
public class CheckParameterAspect {
/**
* 定义切入点,切入点为 com.example.demo.aop.AopController 中的所有函数
*通过 @Pointcut 注解声明频繁使用的切点表达式
*/
@Pointcut("execution(public * cn.tjd.springparametercheck.controller.*.*(..)))")
public void CheckParameterAspect(){
}
/**
* @description 在连接点执行之前执行的通知
*/
@Before("CheckParameterAspect()")
public void doBefore(){
System.out.println("前置通知");
}
/**
* @description 在连接点执行完成后执行,不管正常执行完成,还是抛出异常,都会执行返回通知中的内容;
*/
@After("CheckParameterAspect()")
public void doAfter(){
System.out.println("最终通知");
}
/**
* @description 在在连接点正常执行完成后执行,如果连接点抛出异常,则不会执行;
*/
@AfterReturning("CheckParameterAspect()")
public void doAfterReturning(){
System.out.println("正常返回通知");
}
/**
* @description 在连接点抛出异常后执行;
*/
@AfterThrowing("CheckParameterAspect()")
public void doAfterThrowing(){
System.out.println("异常返回通知");
}
/**
* 环绕通知围绕在连接点前后,比如一个方法调用的前后。这种通知是最强大的通知,能在方法调用前后自定义一些操作。
* @param joinPoint
* @return
* @throws Throwable
*/
@Around("CheckParameterAspect()")
public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
System.out.println("环绕通知前部分");
Object proceed = joinPoint.proceed();
System.out.println("环绕通知后部分");
return proceed;
}
}
其中,切入点表达式规则如下: 详解切入点表达式
三. 各类型通知执行的先后顺序
在实际开发中,有时候我们会针对同一个切入点进行多种 Aspect 包装,比如,可以有一个 Aspect 管理对一个方法进行日志打印的通知,而另一个 Aspect 管理对这个方法的一些校验工作。因此,涉及到两类问题:
- 同一个切入点不同通知的执行顺序
- 同一个切入点不同切面的执行顺序
我们在前面的“环绕通知实现”结果中看到,@Around 是先于 @Before 执行的,这就是其中一个问题的引出,即同一个切入点不同通知的执行顺序。来看下面这张图:
可以看到 Aspect1 和 Aspect2 两个切面类中所有通知类型的执行顺序,Method 是具体的切入点,order 代表优先级,它根据一个 int 值来判断优先级的高低,数字越小,优先级越高!所以,不同的切面,实际上是环绕于切入点的同心圆:
4.1 如何改变切面的优先级
使用 @Order 注解可以指定切面的优先级。
@Order 注解可以使用在类或方法上,但是,直接作用于方法上是无法奏效的,目前的使用方法都是通过标记在切面类上,来实现两个切面的优先级。
@Order 注解接收一个 int 类型的参数,这个参数可以是任意整型数值,数值小的,优先级高。
/*
* 可以使用 @Order 注解指定切面的优先级,值越小优先级越高
* */
@Order(2)
@Component
@Aspect
public class LoggingAspect {
......
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论