> 文章列表 > Spring系列(八) --- 详述 SpringAOP--面向切面编程的相关概念及基本操作

Spring系列(八) --- 详述 SpringAOP--面向切面编程的相关概念及基本操作

Spring系列(八) --- 详述 SpringAOP--面向切面编程的相关概念及基本操作

AOP 其实就是针对程序中的某一个类或者某一个功能做统一的处理, 如针对登录功能在前后端之间可以做一些验证操作, 验证用户名或者密码是否正确.

SpringAOP

  • ♞ 相关概念
  • ♞♞ 具体操作步骤
  • ♞♞♞ 关于 AspectJ 表达式

♞ 相关概念

  • 切面: 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, 描述拦截执行的时机和具体的方法实现;

@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 表达式

在这里插入图片描述
如:

  • 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.