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等分布式日志解決方法,好吧,這些還有待於自己部署環境去嘗試。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM