开发环境为 IDEA,jdk1.8,Maven,SpringBoot2.1.3
AOP使用场景很多,此示例场景为对 web 请求进行日志记录
一、在pom文件中导入AOP依赖
<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-aop -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
二、定义切面类,实现所需功能.根据需求,切面类可定义多个,且可以自定义切面类的执行顺序.
/**
* 简单的aop日志配置
*
* @author YoonaLt
* @date 2019/10/29
*/
@Aspect // 标记此类为切面类
@Component
@Slf4j
@Order(value = 2) // 切面类执行顺序权重
public class LogAspect {
/**
* 定义切入点,可以定义多个。@After(),@Before()等只需填写方法名"pointCut()","pointCut1()","pointCut2()"即可.
* <p>
* execution()的一些含义例如:
* execution(public * com.yoona.aop.*.*(..)),"com.yoona.aop"包下不限返回值的公共方法执行
* execution(* my*(..)),任何一个以"my"开头的方法执行
* execution(* com.yoona.aop.AopController.*(..)),AopController接口下任意方法执行
* 在多个表达式之间使用 ||,or表示"或",使用 &&,and表示"与",!表示"非".例如:execution()||execution()
* <p>
* 还有一些其他表达式,如within(),this(),target(),args(),bean()等,与execution()使用略有差异,这里就不一一介绍了.
* 需要注意的是,当表达式书写错误时,会抛出异常:warning no match for this type name:com.xx.xx [Xlint:invalidAbsoluteTypeName]
*/
@Pointcut("execution(* com.yoona.aop.AopController.*(..))")
public void pointCut() {
}
/**
* 也可以直接定义切入点,@Before("execution(public * com.yoona.*.*(..))"),这样就不必定义切入点 @Pointcut 了.
*
* @param joinPoint 连接点,可以获取切入点方法的一些信息
*/
@Before("pointCut()")
public void atBefore(JoinPoint joinPoint) {
log.debug(" @Before 在方法执行前执行");
log.debug("切入点的方法名为 " + joinPoint.getSignature().getName());
}
/**
* 方法结束后执行,无论是正常结束还是抛出异常都会执行.
*/
@After("pointCut()")
public void atAfter() {
log.debug(" @After 方法执行......");
}
/**
* 方法正常返回后执行
*
* @param o 方法返回的值
*/
@AfterReturning(pointcut = "pointCut()", returning = "o")
public void atAfterReturning(Object o) {
log.debug(" @AfterReturning 方法执行......");
log.debug("方法的返回值为" + o.toString());
}
/**
* 方法抛出异常时执行
*
* @param t 方法抛出的异常
*/
@AfterThrowing(pointcut = "pointCut()", throwing = "t")
public void atAfterThrowing(Throwable t) {
log.debug(" @AfterThrowing 方法抛出异常时执行......");
log.debug("方法抛出的异常为" + t.toString());
}
}
/**
* @author YoonaLt
* @date 2019/10/29
* 再定义一个执行其他功能的切面类
*/
@Aspect
@Component
@Slf4j
@Order(value = 1)
public class OtherAspect {
/**
* 其他功能切面类
*/
@Before("execution(* com.yoona.aop.AopController.*(..))")
public void atBefore() {
RequestAttributes ra = RequestContextHolder.getRequestAttributes();
ServletRequestAttributes sra = (ServletRequestAttributes) ra;
HttpServletRequest httpServletRequest = sra.getRequest();
String method = httpServletRequest.getMethod();
log.debug("其他功能切面类执行了" + "\nMethod:" + method + "\nCache-Control:" + httpServletRequest.getHeader("Cache-Control"));
}
}
三、测试接口
/**
* aop测试接口
*
* @author YoonaLt
* @date 2019/10/29
*/
@Slf4j
@RestController
@RequestMapping(value = "aop")
public class AopController {
@GetMapping(value = "test")
public Integer aopTest() {
log.debug("测试方法执行了");
// 使方法抛出异常
int i = 10 / 0;
return 10;
}
}
四、Run:
访问接口