Spring Boot 使用 AOP 记录日志

开发 前端
在项目开发中经常,日志系统是必不可少的,特别是管理系统,对于重要的操作都会有操作日志,然而这个操作不需要我们在相应的方法中一个一个的去实现,这肯定是不合适的,这样的操作无疑是加大了开发量,而且不易维护,所以实际项目中总是利用AOP(Aspect Oriented Programming)即面向切面编程来记录系统中的操作日志。

[[384373]]

本文转载自微信公众号「武培轩」,作者武培轩 。转载本文请联系武培轩公众号。

在项目开发中经常,日志系统是必不可少的,特别是管理系统,对于重要的操作都会有操作日志,然而这个操作不需要我们在相应的方法中一个一个的去实现,这肯定是不合适的,这样的操作无疑是加大了开发量,而且不易维护,所以实际项目中总是利用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 目录下。

责任编辑:武晓燕 来源: 武培轩
相关推荐

2022-02-08 17:07:54

Spring BooSpring Aop日志记录

2022-02-17 13:39:09

AOP接口方式

2021-08-11 05:00:48

Spring 日志手段

2024-09-02 00:27:51

SpringAOP自定义

2022-09-26 10:01:04

SpringAOP日志

2009-06-19 11:09:27

Spring AOP

2023-09-13 08:56:51

2022-05-12 11:38:26

Java日志Slf4j

2021-05-18 07:30:36

开发Spring Boot日志

2009-06-19 13:28:30

Spring AOPSpring 2.0

2022-06-07 07:58:45

SpringSpring AOP

2012-07-11 14:31:16

SpringAop

2019-04-15 08:32:25

Spring Boot日志门面模式

2020-10-18 08:51:18

Spring Boot

2023-05-11 12:40:00

Spring控制器HTTP

2009-06-22 10:41:34

Spring.AOP

2022-06-08 08:04:28

Springservicerepository

2022-02-09 20:39:52

Actuator应用监控

2021-09-15 16:20:02

Spring BootFilterJava

2023-10-07 10:08:54

点赞
收藏

51CTO技术栈公众号