SpringBoot自定义注解、AOP打印日志

释放双眼,带上耳机,听听看~!

前言

       在SpringBoot中使用自定义注解、aop切面打印web请求日志。主要是想把controller的每个request请求日志收集起来,调用接口、执行时间、返回值这几个重要的信息存储到数据库里,然后可以使用火焰图统计接口调用时长,平均响应时长,以便于我们对接口的调用和执行情况及时掌握。

添加依赖

  <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter</artifactId>
      <version>2.1.4.RELEASE</version>
    </dependency>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-web</artifactId>
      <version>2.1.4.RELEASE</version>
    </dependency>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-aop</artifactId>
      <version>2.1.4.RELEASE</version>
    </dependency>
    <dependency>
      <groupId>com.google.code.gson</groupId>
      <artifactId>gson</artifactId>
      <version>2.8.5</version>
    </dependency>

 

自定义注解

import java.lang.annotation.*;

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
@Documented
public @interface WebLogger {

    String value() default \"\";
}

  

AOP定义切面、切点

      在实现切面之前先要了解几个aop的注解:

  •  @Aspect、
  •  @Pointcut 定义切点,后面跟随一个表达式,表达式可以是一个注解,也可以具体到方法级别。
  •  @Before
  •  @After
  •  @Around

      实现切面,在before方法里统计request请求相关参数,在around方法里计算接口调用时间。这里统计请求的参数时有个bug,joinpoint.getArgs返回值是一个Object数组,但是数组里只有参数值,没有参数名。还没找到解决办法。

@Aspect
@Component
public class WebLoggerAspect {

    @Pointcut(\"@annotation(com.zhangfei.anno.WebLogger)\"
    public void log() {}

    @Around(\"log()\")
    public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable {
        long startTime=System.currentTimeMillis();

        Object result=joinPoint.proceed();
        System.out.println(\"Response:\"+new Gson().toJson(result));
        System.out.println(\"耗时:\"+(System.currentTimeMillis()-startTime));

        return result;
    }

    @Before(\"log()\")
    public void doBefore(JoinPoint joinPoint) {
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();

        System.out.println(\"==================Start=================\");
        System.out.println(\"URL:\" + request.getRequestURL().toString());
        System.out.println(\"Description:\" + getLogValue(joinPoint));
        System.out.println(\"Method:\" + request.getMethod().toString());

        //打印controller全路径及method
        System.out.println(\"Class Method:\" + joinPoint.getSignature().getDeclaringTypeName() + \",\" + joinPoint.getSignature().getName());
        System.out.println(\"客户端IP:\" + request.getRemoteAddr());

        System.out.println(\"请求参数:\" + new Gson().toJson(joinPoint.getArgs()));

    }

    private String getLogValue(JoinPoint joinPoint) {
        MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
        Method method = methodSignature.getMethod();

        WebLogger webLogger = method.getAnnotation(WebLogger.class);

        return webLogger.value();
    }

    @After(\"log()\")
    public void doAfter() {
        System.out.println(\"==================End=================\");
    }
} 

怎么使用注解?

      这里就直接在你的web请求方法上直接添加WebLogger注解

@Controller
@RequestMapping(\"/student\")
public class StudentController {

    private final Logger logger= LoggerFactory.getLogger(StudentController.class);

    @GetMapping(\"/list\")
    @WebLogger(\"学生列表\")
    public @ResponseBody  List<Student> list(){
        ArrayList<Student> list=new ArrayList<>();
        Student student0=new Student(1,\"kobe\",30);
        Student student1=new Student(2,\"james\",30);
        Student student2=new Student(3,\"rose\",30);

        list.add(student0);
        list.add(student1);
        list.add(student2);

        return list;
    }

    @WebLogger(\"学生实体\")
    @RequestMapping(\"/detail\")
    public @ResponseBody Student student(int id){
        return new Student(1,\"kobe\",30);
    }

}

 

切面日志输出效果

SpringBoot自定义注解、AOP打印日志

 

总结

        从头条上一位朋友文章评论上看到有人提出,在分布式部署的环境中,出现高并发时日志打印会出现错乱的情况,这里还需要把线程id或者声明一个guid, 存入ThreadLoal中统计使用。当然更多的人简历还是使用ELK等分布式日志解决方法,好吧,这些还有待于自己部署环境去尝试。

给TA打赏
共{{data.count}}人
人已打赏
随笔日记

以太坊之账户管理

2020-11-9 4:49:52

随笔日记

详解redis持久化

2020-11-9 4:49:54

0 条回复 A文章作者 M管理员
    暂无讨论,说说你的看法吧
个人中心
购物车
优惠劵
今日签到
有新私信 私信列表
搜索