Spring AOP(Aspect-Oriented Programming)是Spring框架提供的一种面向切面编程的技术。它通过将横切关注点(例如日志记录、事务管理、安全性检查等)从主业务逻辑代码中分离出来,以模块化的方式实现对这些关注点的管理和重用。在Spring AOP中,切面(Aspect)是一个模块化的关注点,它可以跨越多个对象,例如日志记录、事务管理等。切面通过定义切点(Pointcut)和增强(Advice)来介入目标对象的方法执行过程。切点是一个表达式,用于匹配目标对象的一组方法,在这些方法执行时切面会被触发。一般来说切点表达式是一个固定的文件坐标,如下
// 第一种
// 切入点表达式
@Pointcut("execution(* com.example.manage.service.*.*(..))")
public void Log() {
}
@Around("Log()")
public Object recordTime(ProceedingJoinPoint joinPoint) throws Throwable {
.............// AOP代码
}
// 第二种
// 切入点坐标直接写入
@Around("execution(* com.example.manage.service.*.*(..))")
public Object recordTime(ProceedingJoinPoint joinPoint) throws Throwable {
.............// AOP代码
}
- 前置增强(Before Advice):在目标方法执行之前执行的逻辑。
- 后置增强(After Advice):在目标方法执行之后执行的逻辑,不管目标方法是否抛出异常。
- 返回增强(After Returning Advice):在目标方法正常返回时执行的逻辑。
- 异常增强(After Throwing Advice):在目标方法抛出异常时执行的逻辑。
- 环绕增强(Around Advice):在目标方法执行前后都可以执行的逻辑,它可以完全控制目标方法的执行。
上文所使用的是 @Around,在目标方法执行前执行AOP业务逻辑,等目标方法执行完成后,在执行一段AOP业务逻辑,中间通过Object result = joinPoint.proceed();进行业务上下文分割
// 目标方法执行前业务逻辑
// 如目标方法执行总耗时长
Long begin = System.currentTimeMillis();
// 目标方法开始执行
Object result = joinPoint.proceed();
// 目标方法执行后业务逻辑
Long end = System.currentTimeMillis();
Long costTime = end - begin;
// 并且在AOP业务执行完后一定要返回目标方法的执行结果
return result;
如果想要实现更加解耦提高代码复用性的AOP业务代码,则需要对切点进行优化,目前的切点表达式只能是固定某个方法层面,并不能刻意的去针对某一方法进行AOP,以下是动态切点思路
1、我们先自定义一个注解接口MyLog,需要使用@interface关键词,以及其上面的两个注解
@Retention(RetentionPolicy.RUNTIME)// 运行时生效
@Target(ElementType.METHOD)// 作用在哪些地方生效--方法上
@Retention(RetentionPolicy.RUNTIME)// 运行时生效
@Target(ElementType.METHOD)// 作用在哪些地方生效--方法上
public @interface MyLog {
}
2、在切入点表达式中直接将自定义接口MyLog坐标写入
// 切入点坐标直接写入
@Around("@annotation(com.example.aop.MyLog)")
public Object recordTime(ProceedingJoinPoint joinPoint) throws Throwable {
.............// AOP代码
}
3、直接在需要执行AOP业务逻辑的方法上添加注解@MyLog即可实现动态切点的AOP业务
// 如删除功能需要执行AOP业务
@MyLog
@DeleteMapping("/{id}")
public Result delete(@PathVariable Integer id) throws Exception {
log.info("根据id删除部门:{}",id);
deptService.delete(id);
return Result.success();
}
主要是由于有自定义注解MyLog中的@Target(ElementType.METHOD)注解实现获取当前方法的执行坐标,从而实现低耦合,执行相同AOP业务时比较简单,只需在目标方法加上自定义注解即可。