AOP 其实就是针对程序中的某一个类或者某一个功能做统一的处理, 如针对登录功能在前后端之间可以做一些验证操作, 验证用户名或者密码是否正确.
♞ 相关概念
- 切面: AOP 主要是针对的某一个功能进行的操作或者定义, 而这个功能就称之为是一个切面, 如用户登录功能, 这就是一个切面;
- 切点: 切点是切面中的一个方法, 或者说是定义 AOP 拦截的规则; 如果切面是一个数据库的话, 那么切点就是数据库中的表;
- 连接点: 所有可能触发 AOP 的都可以称之为连接点; 主要用来匹配切面中的多个点, 如果说切点是表的话, 那么连接点就相当于是表中的一行行的数据;
- 通知: 规定 AOP 执行的时机和执行的方法.
举个例子: 针对用户的登录功能进行校验, 这个用户功能就是一个切面, 可能用户登录的验证需要在多个页面进行校验, 那么这多个页面就相当于是连接点; 当调用用户的登录验证方法时, 整个验证方法就是一个切点, 而方法体就是通知.
♞♞ 具体操作步骤
第一步: 添加 SpringAOP 依赖;
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
<version>2.7.4</version>
</dependency>
第二步: 添加切面和切点;
@Aspect // 当前是一个切面
@Component
public class UserAspect {
// 设置拦截规则, Pointcut 就是一个切点
@Pointcut("execution(* com.example.demo.controller.UserController.*(..))")
public void pointcut() {
}
}
*代表着在 UserController 中的所有方法都要拦截, 后面的 * (…) 指的是可以添加拦截条件, 如 (String, Integer) 两种类型就代表只拦截 UserController 里面的 (String, Integer) 类型的方法.
第三步: 定义通知 Advice, 描述拦截执行的时机和具体的方法实现;文章来源:https://www.toymoban.com/news/detail-405609.html
@Aspect // 当前是一个切面
@Component
public class UserAspect {
// 设置拦截规则
@Pointcut("execution(* com.example.demo.controller.UserController.*(..))")
public void pointcut() {
}
/**
* 定义 pointcut 切点的前置通知
* 在执行目标方法之前执行的方法就是前置通知
*/
@Before("pointcut()")
public void doBefore() {
System.out.println("前置通知: 执行了前置通知!");
}
/**
* 针对 pointcut 切点的后置通知
*/
@After("pointcut()")
public void doAfter() {
System.out.println("后置通知: 执行了后置通知!");
}
/**
* AfterReturning
* 在后置通知之前执行的
*/
@AfterReturning("pointcut()")
public void doAfterReturning() {
System.out.println("执行了 AfterReturning 方法!");
}
/**
* AfterThrowing: 目标方法抛出异常后调用
* 只有报了异常之后才会执行, 执行在 方法之后,
* 执行了 AfterThrowing 后, 将不会执行 AfterReturning
*/
@AfterThrowing("pointcut()")
public void doAfterThrowing() {
System.out.println("执行了 AfterThrowing 方法!");
}
/**
* 环绕通知(将所有通知和方法全部包围起来了)
*/
@Around("pointcut()")
public Object doAround(ProceedingJoinPoint joinPoint) {
// Spring 中的时间统计对象
StopWatch stopWatch = new StopWatch();
Object result = null;
System.out.println("环绕通知: 前置方法!");
try {
stopWatch.start(); // 统计方法的执行时间: 开启计时
// 执行目标方法, 以及目标方法所对应的相应的通知
result = joinPoint.proceed();
stopWatch.stop(); // 统计方法的执行时间: 停止计时
} catch (Throwable e) {
e.printStackTrace();
}
System.out.println("环绕通知: 后置方法!");
System.out.println(joinPoint.getSignature().getName() + " 方法执行花费的时间: " +
stopWatch.getTotalTimeMillis() + "ms");
return result;
}
}
♞♞♞ 关于 AspectJ 表达式
如:文章来源地址https://www.toymoban.com/news/detail-405609.html
- execution(* com.example.demo.User.*(. .)) : 匹配 User 类下的所有方法;
- execution(* com.example.demo.User+.*(. .)) : 匹配该类的子类及该类的所有方法;
- execution(* com.example.* .*(. .)) : 匹配 com.example 包下的所有类的所有方法;
- execution(* com.example. .* .*(. .)) : 匹配 com.example 包下及子孙包下所有类的所有方法;
- execution(* addUser(String, int)) : 匹配 addUser 方法, 且第一个参数类型是 String, 第二个参数类型是 int.
到了这里,关于Spring系列(八) --- 详述 SpringAOP--面向切面编程的相关概念及基本操作的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!