zoukankan      html  css  js  c++  java
  • 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);
        }
    
    }

    切面日志输出效果

    总结

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

  • 相关阅读:
    printcap
    browser-ua
    PHP 开发 APP 接口 学习笔记与总结
    Java实现 LeetCode 72 编辑距离
    Java实现 LeetCode 72 编辑距离
    Java实现 LeetCode 72 编辑距离
    Java实现 LeetCode 71 简化路径
    Java实现 LeetCode 71 简化路径
    Java实现 LeetCode 71 简化路径
    Java实现 LeetCode70 爬楼梯
  • 原文地址:https://www.cnblogs.com/sword-successful/p/10850168.html
Copyright © 2011-2022 走看看