文章目录
AOP
- 通过预编译方式和运行时动态代理实现在不修改源代码的情况下,给程序统一添加功能的技术
- 将日志记录,性能统计,安全控制,事务处理,异常处理等代码从业务逻辑代码中划分出来
- 允许你把遍布应用各处的功能分离出来形成可重用组件
实现方式
预编译
运行时动态代理
- JDK代理
- CGLIB动态代理
使用方式
依赖引入
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
主要注解
@Aspect
作用是把当前类标识为一个切面供容器读取
package com.example.demo.config;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import com.fasterxml.jackson.databind.ObjectWriter;
@Component
@Aspect
public class MyAspect {
}
@Pointcut 声明切入点
切入点生命十分灵活,详细内容可以参考
@Pointcut语法详解
execution 格式
execution(modifiers-pattern? ret-type-pattern declaring-type-pattern? name-pattern(param-pattern)throws-pattern?)
语法
- 修饰符匹配(modifier-pattern?)
- 返回值匹配(ret-type-pattern)可以为
*
表示任何返回值,全路径的类名等 - 类路径匹配(declaring-type-pattern?)
- 方法名匹配(name-pattern)可以指定方法名 或者
*
代表所有,set*
代表以set开头的所有方法 - 参数匹配((param-pattern))可以指定具体的参数类型,多个参数间用
,
隔开,各个参数也可以用*
来表示匹配任意类型的参数,如(String)表示匹配一个String参数的方法;(*,String) 表示匹配有两个参数的方法,第一个参数可以是任意类型,而第二个参数是String类型;可以用(…)表示零个或多个任意参数 - 异常类型匹配(throws-pattern?)
- 其中后面跟着“?”的是可选项
package com.example.demo.config;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import com.fasterxml.jackson.databind.ObjectWriter;
@Component
@Aspect
public class MyAspect {
@Autowired
private ObjectWriter objectWriter;
/**
* com.example.demo.controller包下所有类,所有方法
*/
@Pointcut("execution(* com.example.demo.controller.*.*(..) )")
public void log() {
}
}
通知类型
@Before前置通知
/**
* 前置通知
*
* @param joinPoint joinPoint
* @throws JsonProcessingException JsonProcessingException
*/
@Before("controllerAllMethod()")
public void before(JoinPoint joinPoint) throws JsonProcessingException {
LOGGER.info("before信息:{}", joinPoint.toString());
// joinPoint 包含参数列表和方法信息
LOGGER.info("before入参:{}", objectWriter.writeValueAsString(joinPoint.getArgs()));
}
@AfterReturning 返回之后通知
/**
* 返回之后通知
*
* @param obj 返回对象
* @throws JsonProcessingException JsonProcessingException
*/
@AfterReturning(value = "controllerAllMethod()", returning = "obj")
public void afterReturning(Object obj) throws JsonProcessingException {
LOGGER.info("AfterReturning:{}", objectWriter.writeValueAsString(obj));
}
@AfterThrowing 异常之后通知
/**
* 异常之后通知
*
* @param ex 异常
* @throws JsonProcessingException JsonProcessingException
*/
@AfterThrowing(value = "controllerAllMethod()", throwing = "ex")
public void afterThrowing(Exception ex) throws JsonProcessingException {
LOGGER.info("afterThrowing:{}", objectWriter.writeValueAsString(ex));
}
@After 最后通知(finally)
/**
* 最后通知(finally)
*/
@After("controllerAllMethod()")
public void after() {
LOGGER.info("after");
}
@Around 环绕通知
/**
* 环绕通知
*
* @param proceedingJoinPoint joinPoint
* @throws JsonProcessingException JsonProcessingException
*/
@Around("controllerAllMethod()")
public Object around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
LOGGER.info("start Around:{}", System.currentTimeMillis());
// 执行方法
final Object proceed = proceedingJoinPoint.proceed();
LOGGER.info("stop Around:{}", System.currentTimeMillis());
return proceed;
}
执行顺序
正常情况
- @Around中
proceedingJoinPoint.proceed()
之前部分 - @Before
- 执行方法
- @AfterReturning
- @After
- @Around中
proceedingJoinPoint.proceed()
之后部分 - @RestControllerAdvice 注解设置的返回值包装器
异常情况
- @Around中
proceedingJoinPoint.proceed()
之前部分 - @Before
- 执行方法 抛出异常
- @AfterThrowing
- @After
- @ExceptionHandler 注解的全局异常捕获器
- @RestControllerAdvice 注解设置的返回值包装器