社区微信群开通啦,扫一扫抢先加入社区官方微信群
社区微信群
本文注重讲解在 Spring Boot 中如何使用 AOP,而不会过多纠结于 AOP 的基础知识,若对 AOP 还不了解的同学可以先看我之前写的这篇文章 Spring 中的 AOP 详解
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
在我们引入 AOP 依赖包之后,并不需要去做其他配置,因为 Spring Boot 已经帮我们配置好了。
package edu.szu.test.controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class HelloController {
@RequestMapping("/hello")
public String hello() {
return "hello";
}
@RequestMapping("/end")
public String end() {
return "end";
}
}
这里注意,要想一个类成为切面类,必须添加注解 @Component 和 @Aspect 。
package edu.szu.test.aop;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
@Component
@Aspect
public class LogAspect {
private Logger logger = LoggerFactory.getLogger(LogAspect.class);
// 配置切点
@Pointcut("execution(* edu.szu.test.controller.*.*(..))")
private void point(){};
// 前置通知
@Before("point()")
public void doBefore(JoinPoint joinPoint){
//获取通知的签名
Signature signature = joinPoint.getSignature();
//获取代理方法
String name = signature.getName();
//获取代理类
String className = signature.getDeclaringTypeName();
logger.info("这是一个前置通知:" + "代理方法为" + name + " 代理类为" + className);
}
}
我们这里定义的切点为 edu.szu.test.controller 下的所有函数。
打开浏览器,先输入 http://localhost:8080/hello,再输入 http://localhost:8080/end,发现结果如下
package edu.szu.test.aop;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
@Component
@Aspect
public class LogAspect {
private Logger logger = LoggerFactory.getLogger(LogAspect.class);
// 配置切点
@Pointcut("execution(* edu.szu.test.controller.*.*(..))")
private void point(){};
// 前置通知
@Before("point()")
public void doBefore(JoinPoint joinPoint){
//获取通知的签名
Signature signature = joinPoint.getSignature();
//获取代理方法
String name = signature.getName();
//获取代理类
String className = signature.getDeclaringTypeName();
logger.info("这是一个前置通知:" + "代理方法为" + name + " 代理类为" + className);
}
// 环绕通知
@Around("point()")
public Object around(ProceedingJoinPoint proceedingJoinPoint) {
//获取方法名
String name = proceedingJoinPoint.getSignature().getName();
logger.info("这是一个环绕通知:" + "代理方法为" + name);
try {
Object obj = proceedingJoinPoint.proceed();
logger.info("这是一个环绕通知:方法已被执行");
return obj;
} catch (Throwable throwable) {
throwable.printStackTrace();
logger.error("这是一个环绕通知:出错了!");
}
return null;
}
// 后置通知
@After("point()")
public void after(JoinPoint joinPoint) {
//获取通知的签名
Signature signature = joinPoint.getSignature();
//获取代理方法
String name = signature.getName();
//获取代理类
String className = signature.getDeclaringTypeName();
logger.info("这是一个后置通知:" + "代理方法为" + name + " 代理类为" + className);
}
// 后置返回通知,其中 keys 为返回值的信息
@AfterReturning(value = "point()",returning = "keys")
public void afterReturning(JoinPoint joinPoint,Object keys){
logger.info("这是一个后置返回通知:返回值为" + keys.toString());
}
// 后置异常通知
@AfterThrowing(value = "point()",throwing = "exception")
public void afterThrowing(JoinPoint joinPoint,Throwable exception){
//获取通知的签名
Signature signature = joinPoint.getSignature();
//获取代理方法
String name = signature.getName();
logger.error("这是一个后置异常通知:" + "代理方法为" + name);
logger.error("这是一个后置异常通知:" + exception);
}
}
还是来谈谈环绕通知吧,这是最强大的一种通知类型。环绕通知可以在方法调用前后完成自定义的行为,它也会选择是否继续执行连接点或者直接返回它自己的返回值或抛出异常来结束执行,甚至可以决定执行时是否需要替换方法参数以及执行完毕是否需要替换返回值。调用 ProceedingJoinPoint 的 proceed() 方法会导致后台的连接点方法执行。
先来测试正常的控制器
@RequestMapping("/hello")
public String hello() {
//int i = 1/0;
return "hello";
}
结果如下
再故意在控制器中抛出异常
@RequestMapping("/hello")
public String hello() {
int i = 1/0;
return "hello";
}
结果如下
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!