本文转载自微信公众号「武培轩」,作者武培轩 。转载本文请联系武培轩公众号。
在项目开发中经常,日志系统是必不可少的,特别是管理系统,对于重要的操作都会有操作日志,然而这个操作不需要我们在相应的方法中一个一个的去实现,这肯定是不合适的,这样的操作无疑是加大了开发量,而且不易维护,所以实际项目中总是利用AOP(Aspect Oriented Programming)即面向切面编程来记录系统中的操作日志。
下面就来介绍如何在 Spring Boot 中 使用 AOP 记录日志:
加入依赖
首先加入 AOP 依赖:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
- 1.
- 2.
- 3.
- 4.
创建日志注解类
创建一个日志注解类,这样就可以在需要记录日志的方法上加上注解就可以记录日志了,注解内容如下:
@Target({ElementType.PARAMETER, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface AopLogger {
String describe() default "";
}
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
配置 AOP 切面
定义一个 AopLoggerAspect 切面类,用 @Aspect 声明该类为切面类。
@Component
public class AopLoggerAspect {
private final Logger logger = LoggerFactory.getLogger(this.getClass());
@Pointcut("@annotation(com.wupx.aop.logger.annotation.AopLogger)")
public void aopLoggerAspect() {
}
/**
* 环绕触发
*
* @param point
* @return
*/
@Around("aopLoggerAspect()")
public Object doAround(ProceedingJoinPoint point) {
RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes) requestAttributes;
HttpServletRequest request = servletRequestAttributes.getRequest();
Object result = null;
long startTime = System.currentTimeMillis();
try {
result = point.proceed();
} catch (Throwable throwable) {
throwable.printStackTrace();
logger.error(throwable.getMessage());
}
String describe = getAopLoggerDescribe(point);
if (StringUtils.isBlank(describe)) {
describe = "-";
}
// 打印请求相关参数
logger.info("========================================== Start ==========================================");
logger.info("Describe : {}", describe);
// 打印请求 url
logger.info("URL : {}", request.getRequestURL());
logger.info("URI : {}", request.getRequestURI());
// 打印 Http method
logger.info("HTTP Method : {}", request.getMethod());
// 打印调用 controller 的全路径以及执行方法
logger.info("Class Method : {}.{}", point.getSignature().getDeclaringTypeName(), point.getSignature().getName());
// 打印请求的 IP
logger.info("IP : {}", request.getRemoteAddr());
// 打印请求入参
logger.info("Request Args : {}", point.getArgs());
// 打印请求出参
logger.info("Response Args : {}", result);
logger.info("Time Consuming : {} ms", System.currentTimeMillis() - startTime);
logger.info("=========================================== End ===========================================");
return result;
}
/**
* 获取注解中对方法的描述信息
*
* @param joinPoint 切点
* @return describe
*/
public static String getAopLoggerDescribe(JoinPoint joinPoint) {
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
Method method = signature.getMethod();
AopLogger controllerLog = method.getAnnotation(AopLogger.class);
return controllerLog.describe();
}
}
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
- 15.
- 16.
- 17.
- 18.
- 19.
- 20.
- 21.
- 22.
- 23.
- 24.
- 25.
- 26.
- 27.
- 28.
- 29.
- 30.
- 31.
- 32.
- 33.
- 34.
- 35.
- 36.
- 37.
- 38.
- 39.
- 40.
- 41.
- 42.
- 43.
- 44.
- 45.
- 46.
- 47.
- 48.
- 49.
- 50.
- 51.
- 52.
- 53.
- 54.
- 55.
- 56.
- 57.
- 58.
- 59.
- 60.
- 61.
- 62.
- 63.
- 64.
- 65.
其中 「@Pointcut」 是定义一个切点,后面跟随一个表达式,表达式可以定义为某个 package 下的方法,也可以是自定义注解等。
「@Around」 为在切入点前后织入代码,并且可以自由的控制何时执行切点。
测试
接下来编写 Controller 层来进行测试:
@RestController
@RequestMapping("/user")
public class UserController {
private final UserService userService;
public UserController(UserService userService) {
this.userService = userService;
}
@PostMapping
@AopLogger(describe = "添加用户")
public String addUser(@RequestBody User user) {
UserEntity userEntity = new UserEntity();
BeanUtils.copyProperties(user, userEntity);
return userService.addUser(userEntity);
}
}
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
- 15.
- 16.
- 17.
- 18.
只需要在接口上填写 @AopLogger 就可以记录操作日志。
启动服务,通过 PostMan 请求 http://localhost:8080/user 接口,输出的日志如下所示:
可以看到把入参、出参以及接口信息都记录了下来,是不是很简单呢,只需要简单几步就可以实现 AOP 日志,大家可以自己实践下。
本文的完整代码在 https://github.com/wupeixuan/SpringBoot-Learn 的 aop-logger 目录下。