1. 程式人生 > 程式設計 >Spring Boot如何通過自定義註解實現日誌列印詳解

Spring Boot如何通過自定義註解實現日誌列印詳解

前言

在我們日常的開發過程中通過列印詳細的日誌資訊能夠幫助我們很好地去發現開發過程中可能出現的Bug,特別是在開發Controller層的介面時,我們一般會打印出Request請求引數和Response響應結果,但是如果這些列印日誌的程式碼相對而言還是比較重複的,那麼我們可以通過什麼樣的方式來簡化日誌列印的程式碼呢?

SpringBoot 通過自定義註解實現許可權檢查可參考我的部落格:SpringBoot 通過自定義註解實現許可權檢查

正文

Spring AOP

Spring AOP 即面向切面,是對OOP面向物件的一種延伸。

AOP機制可以讓開發者把業務流程中的通用功能抽取出來,單獨編寫功能程式碼。在業務流程執行過程中,Spring框架會根據業務流程要求,自動把獨立編寫的功能程式碼切入到流程的合適位置。

我們通過AOP機制可以實現:Authentication 許可權檢查、Caching 快取、Context passing 內容傳遞、Error handling 錯誤處理、日誌列印等功能,這裡我們講一下怎麼用Spring AOP來實現日誌列印。

SpringBoot通過自定義註解實現日誌列印

Maven依賴

<!--lombok-->
<dependency>
 <groupId>org.projectlombok</groupId>
 <artifactId>lombok</artifactId>
 <version>1.18.2</version>
 <optional>true</optional>
</dependency>

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

ControllerMethodLog.class自定義註解

  • @Retention: 用來修飾註解,是註解的註解,稱為元註解。
  • @Target:用來說明物件的作用範圍
  • @Documented:用來做標記使用
/**
* 自定義註解用於列印Controller層方式日誌
*/
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
public @interface ControllerMethodLog {
}

這裡特別講一下@Retention,按生命週期來劃分可分為3類:

  • RetentionPolicy.SOURCE:註解只保留在原始檔,當Java檔案編譯成class檔案的時候,註解被遺棄(執行時去動態獲取註解資訊);
  • RetentionPolicy.CLASS:註解被保留到class檔案,但jvm載入class檔案時候被遺棄,這是預設的生命週期(在編譯時進行一些預處理操作);
  • RetentionPolicy.RUNTIME:註解不僅被儲存到class檔案中,jvm載入class檔案之後,仍然存在(做一些檢查性的操作);

這3個生命週期分別對應於:Java原始檔(.java檔案) —> .class檔案 —> 記憶體中的位元組碼。

Spring AOP切面方法的執行順序

這裡簡單介紹一下,切面的執行方法和其執行順序:

  • @Around 通知方法將目標方法封裝起來
  • @Before 通知方法會在目標方法呼叫之前執行
  • @After 通知方法會在目標方法返回或者異常後執行
  • @AfterReturning 通知方法會在目標方法返回時執行
  • @Afterthrowing 通知方法會在目標方法丟擲異常時執行

這裡以一個返回正常的情況為例:(異常替換最後一步即可)

Spring Boot如何通過自定義註解實現日誌列印詳解

ControllerMethodLogAspect.class:用於列印日誌的切面定義類

注意要在啟動類掃描這個class,並且新增 @EnableAspectJAutoProxy(proxyTargetClass = true)

@Slf4j
@Component
@Aspect
public class ControllerMethodLogAspect {

 @Pointcut("@annotation(com.xiyuan.demo.annotation.ControllerMethodLog)")
 public void pointCut() {
 }

 /**
 * 在切點執行前執行該方法
 */
 @Before("pointCut()")
 public void doBefore(JoinPoint joinPoint) {
 MethodSignature signature = (MethodSignature) joinPoint.getSignature();
 Method method = signature.getMethod();
 ControllerMethodLog annotation = method.getAnnotation(ControllerMethodLog.class);
 if (Objects.isNull(annotation)) {
  return;
 }
 String methodName = method.getDeclaringClass().getSimpleName() + "." + method.getName();
 log.info("start {}:入參:{}",methodName,JSON.toJSONString(joinPoint.getArgs()));
 }


 /**
 * 在切點執行後,無異常時執行該方法
 *
 * @param joinPoint
 * @param result
 */
 @AfterReturning(value = "pointCut()",returning = "result")
 public void afterReturn(JoinPoint joinPoint,Object result) {
 MethodSignature signature = (MethodSignature) joinPoint.getSignature();
 Method method = signature.getMethod();
 ControllerMethodLog annotation = method.getAnnotation(ControllerMethodLog.class);
 if (Objects.isNull(annotation)) {
  return;
 }
 String methodName = method.getDeclaringClass().getSimpleName() + "." + method.getName();
 log.info("end {}:響應:{}",JSON.toJSONString(result));
 }


}

驗證

getUserById:根據id獲取使用者的資訊

@GetMapping("/getUserById")
@ApiOperation(value = "根據使用者id獲取使用者")
@ControllerMethodLog
public ResponseResult getUserById(@RequestParam(name = "id",required = true) String id) {
 UserInfoPojo userInfoPojo = userService.getUserById(id);
 return ResponseResult.success(userInfoPojo,ConstantsUtil.QUERY_SUCCESS);
}

Swagger介面資訊如下:

Spring Boot如何通過自定義註解實現日誌列印詳解

IDEA控制檯列印資訊如下:

Spring Boot如何通過自定義註解實現日誌列印詳解

總結

到此這篇關於Spring Boot如何通過自定義註解實現日誌列印的文章就介紹到這了,更多相關SpringBoot自定義註解實現日誌列印內容請搜尋我們以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援我們!