springboot使用自定义注解实现aop切面日志

平时我们在开发过程中,代码出现bug时为了更好的在服务器日志中寻找问题根源,会在接口的首尾打印日志,看下参数和返回值是否有问题。但是手动的logger.info() 去编写时工作量较大,这时我们可以使用AOP切面,为所有接口的首尾打印日志。

实现AOP切面日志一般有两种方式:

1、拦截所有接口controller,在首尾打印日志
2、拦截指定注解的接口,为有该注解的接口首尾打印日志

我们尝试用自定义注解来实现AOP日志的打印,这样拥有更高的灵活性。废话不多说,我们开始

1. 导入切面需要的依赖包

<dependency>
      <groupId>org.springframework.boot</groupId>
     <artifactId>spring-boot-starter-aop</artifactId>
</dependency>

2. 自定义注解 AOPLog , 指定注解使用在方法上, 指定在运行时有效

Target:描述了注解修饰的对象范围

  • METHOD:用于描述方法
  • PACKAGE:用于描述包
  • PARAMETER:用于描述方法变量
  • TYPE:用于描述类、接口或enum类型

Retention: 表示注解保留时间长短

  • SOURCE:在源文件中有效,编译过程中会被忽略
  • CLASS:随源文件一起编译在class文件中,运行时忽略
  • RUNTIME:在运行时有效

只有定义为 RetentionPolicy.RUNTIME(在运行时有效)时,我们才能通过反射获取到注解,然后根据注解的一系列值,变更不同的操作。

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
 
/**
 * @author buer
 * @date 2019/12/26
 */
// 指定注解使用在方法上
@Target(ElementType.METHOD)
// 指定生效至运行时
@Retention(RetentionPolicy.RUNTIME)
public @interface AOPLog {
 
    /**
     * 指定是否详情显示
     * true 显示详情, 默认false
     *
     * @return
     */
    boolean isDetail() default false;
 
}

3. 设置切面类

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.serializer.SerializerFeature;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
 
import java.lang.reflect.Method;
 
/**
 * @author buer
 * @date 2019/12/26
 * @description //TODO
 */
// 指定切面类
@Aspect
// 注入容器
@Component
public class AOPLogAspect {
 
    private static Logger log = LoggerFactory.getLogger(AOPLogAspect.class);
 
    /**
     * 指定切点, 切点的位置是存在该注解com.xingyun.xybb.demo.annotation.AOPLog
     */
    @Pointcut("@annotation(com.xingyun.xybb.demo.annotation.AOPLog)")
    public void logPointCut() {
    }
 
    /**
     * 环绕通知, 该处写具体日志逻辑
     *
     * @param joinPoint
     */
    @Around("logPointCut()")
    public void logAround(ProceedingJoinPoint joinPoint) {
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        // 获取方法名称
        String methodName = signature.getName();
        // 获取入参
        Object[] param = joinPoint.getArgs();
        StringBuilder sb = new StringBuilder();
        for (Object o : param) {
            sb.append(o).append("; ");
        }
        log.info("进入方法[{}], 参数有[{}]", methodName, sb.toString());
 
        String resp = "";
        try {
            Object proceed = joinPoint.proceed();
            resp = JSON.toJSONString(proceed, SerializerFeature.WriteMapNullValue);
        } catch (Throwable throwable) {
            throwable.printStackTrace();
        }
 
        // 获取方法上的注解,判断如果isDetail值为true,则打印结束日志
        Method method = signature.getMethod();
        AOPLog annotation = method.getAnnotation(AOPLog.class);
        boolean isDetail = annotation.isDetail();
        if (isDetail) {
            log.info("方法[{}]执行结束, 返回值[{}]", methodName, resp);
        }
    }
 
}

4. 编写测试接口, 测试切面日志是否生效

import com.xingyun.xybb.common.response.XyResponseEntity;
import com.xingyun.xybb.demo.annotation.AOPLog;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
 
/**
 * @author buer
 * @date 2019/12/26
 * @description //TODO
 */
@RestController
public class TestAOPLogController {
    
    // 指定注解@AOPLog
    @AOPLog
    @GetMapping("/testAOP")
    public ResponseEntity<?> testAOPLog() {
        return XyResponseEntity.ok();
    }
 
    // 指定注解@AOPLog, 同时isDetail = true
    @AOPLog(isDetail = true)
    @GetMapping("/testAOPLogDetail")
    public ResponseEntity<?> testAOPLogDetail() {
        return XyResponseEntity.ok();
    }
 
}

5. 分别请求两测试接口

http://localhost:8499/demo/testAOP
http://localhost:8499/demo/testAOPLogDetail

控制台打印出

2019-12-26 14:00:56.336  ***.AOPLogAspect    : 进入方法[testAOPLog], 参数有[]
 
2019-12-26 14:01:00.372  ***.AOPLogAspect    : 进入方法[testAOPLogDetail], 参数有[]
2019-12-26 14:01:00.373  ***.AOPLogAspect    : 方法[testAOPLogDetail]执行结束, 返回值[{"body":{"retCode":200,"retEntity":null,"retMsg":"OK"},"headers":{},"statusCode":"OK","statusCodeValue":200}]

由此可看出,AOP切面拦截成功,打印出了日志,同时设置了 isDetail = true 时,打印出了结束日志。

自定义注解实现AOP切面打印日志完成。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • 详解基于SpringBoot使用AOP技术实现操作日志管理

    操作日志对于程序员或管理员而言,可以快速定位到系统中相关的操作,而对于操作日志的管理的实现不能对正常业务实现进行影响,否则即不满足单一原则,也会导致后续代码维护困难,因此我们考虑使用AOP切面技术来实现对日志管理的实现. 文章大致内容: 1.基本概念 2.基本应用 3.日志管理实战 对这几部分理解了,会对AOP的应用应该很轻松. 一.基本概念 项目 描述 Aspect(切面) 跨越多个类的关注点的模块化,切面是通知和切点的结合.通知和切点共同定义了切面的全部内容--它是什么,在何时和何处完成其功

  • springboot配置aop切面日志打印过程解析

    这篇文章主要介绍了springboot配置aop切面日志打印过程解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 一.SpringBoot Aop说明 1. Aop AOP(Aspect-Oriented Programming,面向切面编程),它利用一种"横切"的技术,将那些多个类的共同行为封装到一个可重用的模块.便于减少系统的重复代码,降低模块之间的耦合度,并有利于未来的可操作性和可维护性. 2. AOP相关概念: Aspect

  • SpringBoot AOP处理请求日志打印功能代码实例

    设计原则和思路: 元注解方式结合AOP,灵活记录操作日志 能够记录详细错误日志为运营以及审计提供支持 日志记录尽可能减少性能影响 操作描述参数支持动态获取,其他参数自动记录. 代码实例如下 @Slf4j @Aspect @Configuration public class RequestAopConfig { @Autowired private HttpServletRequest request; private static final ThreadLocal<Long> START_

  • Springboot2 配置AOP日志的方法步骤

    Spring boot2 配置AOP前置增强,后置增强,异常增强,环绕增强,最终增强 关于AOP切面相关具体概念不做过多阐述(概念弄懂有利于理解思想),这是配置AOP的各种增强日志,解决日志嵌套在业务代码的麻烦和不科学 先来个Git demo项目压压惊: https://github.com/zhang-xiao-xiang/boot-aop  (有的更新了一些) 1pom依赖(这里使用log4j2作为日志框架,因为比log4j或者其他日志框架,它效率更高,功能更加强大) <!-- 引入log4

  • 在springboot中使用AOP进行全局日志记录

    目录 前言 1. spring AOP 是什么? 2.spring AOP 能做什么? 3.spring AOP 我能用 AOP 解决什么问题? 一.引入依赖,增加自定义注解 1.引入 maven 依赖 2.增加自定义注解 OperationLog 二.为自定义注解编写切面实现 三.使用自定义日志注解 前言 此前项目上需要对用户的操作进行日志记录,以便后续追踪问题,所以就学习了使用 spring AOP 来进行日志记录. 1. spring AOP 是什么? spring 的两大核心就是 IOC

  • SpringBoot中使用AOP打印接口日志的方法

    前言 AOP 是 Aspect Oriented Program (面向切面)的编程的缩写.他是和面向对象编程相对的一个概念.在面向对象的编程中,我们倾向于采用封装.继承.多态等概念,将一个个的功能在对象中来实现.但是,我们在实际情况中也发现,会有另外一种需求就是一类功能在很多对象的很多方法中都有需要.例如有一些对数据库访问的方法有事务管理的需求,有很多方法中要求打印日志.按照面向对象的方式,那么这些相同的功能要在很多地方来实现或者在很多地方来调用.这就非常繁琐并且和这些和业务不相关的需求耦合太

  • 解析springboot集成AOP实现日志输出的方法

    开发接口系统中主要的一环就是日志输出,如果系统出现问题,日志能帮我们去定位问题,最常见的日志是调用方 所调用的IP 接口地址 对应方法 参数值 以及接口方接收到请求 所返回的参数.如果这需要在每一个controller层去写的话代码过于重复,于是就使用AOP定义切面 对其接口调用前后进行拦截日志输出. 1.加入依赖 <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spr

  • Springboot接口项目如何使用AOP记录日志

    一. 背景 一直想给项目构建一个统一的日志收集系统,先迈出第一步,构建一个日志收集类,用AOP实现无侵入日志收集 二. 环境 1.此随笔内容基于spring boot项目 2.数据库为mysql 5.7.9版本 3.jdk 版本为1.8 三. 说明 此版采用数据库存储,之后考虑使用elasticsearch等工具存储 四. 内容 1.构建日志采集实体类:BaseLogMessage public class BaseLogMessage { private String serverIP; pr

  • 使用SpringBoot+AOP实现可插拔式日志的示例代码

    一.AOP AOP为Aspect Oriented Programming的缩写,意为:面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术. AOP是OOP的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生范型. 二.实现 引入依赖 <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot

  • Springboot使用@Valid 和AOP做参数校验及日志输出问题

    项目背景 最近在项目上对接前端的的时候遇到了几个问题 1.经常要问前端要请求参数 2.要根据请求参数写大量if...else,代码散步在 Controller 中,影响代码质量 3.为了解决问题1,到处记日志,导致到处改代码 解决方案 为了解决这类问题,我使用了@Valid 做参数校验,并使用AOP记录前端请求日志 1.Bean实体类增加注解 对要校验的实体类增加注解,如果实体类中有List结构,就在List上加@Valid @Valid注解 注解 备注 @Null 只能为null @NotNu

随机推荐