1. 程式人生 > >SpringBoot使用AOP統一處理Web請求日誌新增MDC

SpringBoot使用AOP統一處理Web請求日誌新增MDC

AOP是Spring框架中的一個重要內容,它通過對既有程式定義一個切入點,然後在其前後切入不同的執行內容,基於AOP不會破壞原來程式邏輯,因此它可以很好的對業務邏輯的各個部分進行隔離,從而使得業務邏輯各部分之間的耦合度降低,提高程式的可重用性,同時提高了開發的效率。

之前看到公司有的人,在業務邏輯內列印方法的請求引數,新增MDC,請求返回時再列印返回的結果,這種事可以統一寫好,所有地方都用再寫了,並且也能保證程式碼的乾淨整潔。

SpringAOP.java

  1. package com.ruubypay.miss.usercenter.config;  
  2. import com.ruubypay.miss.global.utils.ErrorCodeHelper;  
  3. import com.ruubypay.miss.usercenter.interfaces.models.base.ModelsReturn;  
  4. import javassist.*;  
  5. import javassist.bytecode.CodeAttribute;  
  6. import javassist.bytecode.LocalVariableAttribute;  
  7. import javassist.bytecode.MethodInfo;  
  8. import org.apache.commons.lang3.ArrayUtils;  
  9. import org.aspectj.lang.JoinPoint;  
  10. import org.aspectj.lang.ProceedingJoinPoint;  
  11. import org.aspectj.lang.annotation.*;  
  12. import org.aspectj.lang.reflect.MethodSignature;  
  13. import org.slf4j.Logger;  
  14. import org.slf4j.LoggerFactory;  
  15. import org.slf4j.MDC;  
  16. import org.springframework.context.annotation.Configuration;  
  17. import org.springframework.core.annotation.Order;  
  18. import org.springframework.stereotype.Component;  
  19. import org.springframework.web.context.request.RequestContextHolder;  
  20. import org.springframework.web.context.request.ServletRequestAttributes;  
  21. import javax.servlet.http.HttpServletRequest;  
  22. import javax.servlet.http.HttpServletResponse;  
  23. import java.util.Arrays;  
  24. import java.util.Enumeration;  
  25. import java.util.UUID;  
  26. /** 
  27.  * @author: wangsaichao 
  28.  * @date: 2017/10/25 
  29.  * @description: 配置切面,配置日誌 和請求引數列印 
  30.  */
  31. @Aspect
  32. //@Order(-99) // 控制多個Aspect的執行順序,越小越先執行,為了要在Spring的事務之後執行,所以給他設定99
  33. @Configuration
  34. publicclass SpringAOP {  
  35.     privatestaticfinal Logger logger = LoggerFactory.getLogger(SpringAOP.class);  
  36.     /** 
  37.      * 定義切點Pointcut 
  38.      * 第一個*號:表示返回型別, *號表示所有的型別 
  39.      * 第二個*號:表示類名,*號表示所有的類 
  40.      * 第三個*號:表示方法名,*號表示所有的方法 
  41.      * 後面括弧裡面表示方法的引數,兩個句點表示任何引數 
  42.      */
  43.     @Pointcut("execution(* com.ruubypay.miss.usercenter.interfaces.controller..*.*(..))")  
  44.     publicvoid executionService() {  
  45.     }  
  46.     /** 
  47.      * 方法呼叫之前呼叫 
  48.      * @param joinPoint 
  49.      */
  50.     @Before(value = "executionService()")  
  51.     publicvoid doBefore(JoinPoint joinPoint){  
  52.         //新增日誌列印
  53.         String requestId = String.valueOf(UUID.randomUUID());  
  54.         MDC.put("requestId",requestId);  
  55.         logger.info("=====>@Before:請求引數為:{}",Arrays.toString(joinPoint.getArgs()));  
  56.     }  
  57.     /** 
  58.      * 方法之後呼叫 
  59.      * @param joinPoint 
  60.      * @param returnValue 方法返回值 
  61.      */
  62.     @AfterReturning(pointcut = "executionService()",returning="returnValue")  
  63.     publicvoid  doAfterReturning(JoinPoint joinPoint,Object returnValue){  
  64.         logger.info("=====>@AfterReturning:響應引數為:{}",returnValue);  
  65.         // 處理完請求,返回內容
  66.         MDC.clear();  
  67.     }  
  68.     /** 
  69.      * 統計方法執行耗時Around環繞通知 
  70.      * @param joinPoint 
  71.      * @return 
  72.      */
  73.     @Around("executionService()")  
  74.     public Object timeAround(ProceedingJoinPoint joinPoint) {  
  75.         //獲取開始執行的時間
  76.         long startTime = System.currentTimeMillis();  
  77.         // 定義返回物件、得到方法需要的引數
  78.         Object obj = null;  
  79.         //Object[] args = joinPoint.getArgs();
  80.         try {  
  81.             obj = joinPoint.proceed();  
  82.         } catch (Throwable e) {  
  83.             logger.error("=====>統計某方法執行耗時環繞通知出錯", e);  
  84.         }  
  85.         // 獲取執行結束的時間
  86.         long endTime = System.currentTimeMillis();  
  87.         //MethodSignature signature = (MethodSignature) joinPoint.getSignature();
  88.         //String methodName = signature.getDeclaringTypeName() + "." + signature.getName();
  89.         // 列印耗時的資訊
  90.         logger.info("=====>處理本次請求共耗時:{} ms",endTime-startTime);  
  91.         return obj;  
  92.     }  
  93. }  
一些解釋,在程式碼中已經解釋的很清楚了,這裡介紹一下MDC.put("requestId",requestId);

假如你的系統已經上線,有一個客戶的操作有誤,導致出現了一些錯誤,我們可以到日誌中去看一下使用者的這次請求到底是發生了什麼錯誤。我們可以根據根據使用者的手機號或者賬號來定位到日誌的位置,但是下面的處理流程呢。我們知道系統不可能只有一個人在訪問,假如很多人在訪問的話,日誌列印的是很亂的,這時候如果沒有MDC我猜此時此刻你應該處於雪崩狀態。MDC恰到好處的讓你能夠實現在日誌上突如其來的一些需求。

requestId我使用的uuid來作為value值.方便 唯一。在我們根據手機號定位到使用者的請求時,在使用requestId來定位這次的請求流程,具體如下:

可以看到,可以直接定位出這次請求的所有日誌,就算併發很大,只要保證requestId的唯一,就可以定位這次請求的處理過程。

MDC.put("requestId",requestId);之後 還要在日誌中 使用requestId才可以,如下:

===%d{yyyy-MM-dd HH:mm:ss.SSS} %-5level %logger Line:%-3L [%X{requestId}] - %msg%n

最後使用完之後,使用 MDC.clear();來清除這次請求的requestId.

相關推薦

SpringBoot使用AOP統一處理Web請求日誌新增MDC

AOP是Spring框架中的一個重要內容,它通過對既有程式定義一個切入點,然後在其前後切入不同的執行內容,基於AOP不會破壞原來程式邏輯,因此它可以很好的對業務邏輯的各個部分進行隔離,從而使得業務邏輯各部分之間的耦合度降低,提高程式的可重用性,同時提高了開發的效率。之前看到公

Spring Boot2.0之統一處理web請求日誌

試問,你的專案中,如果有幾萬個方法,你還這麼寫log.info("name"+name+",age"+age )日誌麼?low~      所以用AOP呀 1、首先建立個aop的包(aop的依賴jar包要在pom中搞定),把下面類,貼進去:   packa

Spring Boot中使用AOP統一處理Web請求日誌

在spring boot中,簡單幾步,使用spring AOP實現一個攔截器: 1、引入依賴: [html] view plain copy print?<dependency>    <groupId>org.springframework.boot</groupId&g

用SpringBoot搭建個人部落格01-----使用AOP統一處理Web請求日誌

摘要 AOP 是面向切面的程式設計,就是在執行期通過動態代理的方式對程式碼進行增強處理,比較核心的概念有 切點,切面,通知,有關AOP的詳情參考:。 本文要介紹的是在一個SpringBoot專案中如何統一的處理Web請求日誌,基本思想還是採用AOP的方式,攔截請

46. Spring Boot中使用AOP統一處理Web請求日誌【從零開始學Spring Boot】

【視訊&交流平臺】 http://study.163.com/course/introduction.htm?courseId=1004329008&utm_campaign=commission&utm_source=40000000

使用AOP同一處理WEB請求日誌

在實際開發中,我們可能會經常用到log.info(),這句程式碼會出現多次,使程式碼比較冗餘,通過aop原理可以幫助我們減少冗餘程式碼。 需要在pom檔案中引入aop的依賴: <!-- 引入aop依賴 --> <dependency> <groupId>

SpringBoot進階之AOP統一處理http請求日誌

相關注解 1、@Aspect  放在類上面,把該類作為一個切面 2、@Pointcut  放在方法上面,定義一個可被別的方法引用的切入點表示式 3、@Before  放在方法上面,前置通知   方法執行前執行 4、@After   放在方法上面     後置最終通知    

WebUtility(提供在處理 Web 請求時用於編碼和解碼 URL 的方法。)

html second rep eth asp entity utility -s 文本 public static string UrlEncode( string str ) UrlEncode(String) 方法可用來編碼整個 URL,包括查詢字符串值。

Spring Boot:AOP統一處理HTTP請求

版權宣告:博主原創/資料整理,轉載請註明出處!! 首先,AOP (Aspect Oriented Programming )指面向切面程式設計,通過預編譯方式或者執行時刻對目標物件動態地新增功能。 一、Spring Boot中新增AOP依賴 <

SpringBoot AOP 記錄WEB請求日誌

實現AOP的切面主要有以下幾個要素: 使用@Aspect註解將一個java類定義為切面類 使用@Pointcut定義一個切入點,可以是一個規則表示式,比如下例中某個package下的所有函式,也可以是一個註解等。 根據需要在切入點不同位置的切入內容

在Python3.0中使用HTTPServer處理web請求2-獲取請求引數

轉自:http://phyeas.iteye.com/blog/356121 繼上次用HTTPServer寫了一個簡單的HTTPHandler後,我發現如果採用HTTPServer處理WEB請求的話系統沒有提供獲得請求引數的方法(如Java裡的request.getP

Rx系列學習筆記_使用okhttp攔截器統一處理返回請求

之前我們進行了一個簡單的請求。但是我們發現api的所以的Observable的型別都是要進行一個ResponseData包裹。ResponseData的程式碼如下: public class R

Springboot中AOP統一處理請求日誌

alt image pri sys -1 boot 技術分享 ring com 完善上面的代碼: 現在把輸出信息由先前的system.out.println()方式改為由日誌輸出(日誌輸出的信息更全面) Springboot中AOP統一處理請求日誌

Spring Boot使用AOP搭建統一處理請求日誌和使用log4j記錄不同級別的日誌

受http://blog.didispace.com/springbootaoplog/啟發,今天給Spring Boot專案搭建了統一處理請求日誌的切面並引入log4j記錄不同層級日誌。 mark一下這個過程,以及原文中沒有涉及到的一些疑問 一.  新增要使用的依賴&nbs

SSM專案使用AOP建立統一處理請求日誌

由於專案早已完成,所以很多依賴之前就已經倒入,因此並未新增任何依賴,日誌切面類也和連結中的一致。 只是在xml中新增aop支援時踩了大坑。 按照上一篇文章,將WebLogAspect類、log4j.properties檔案匯入後。按照普通Spring專案的規矩,在xml

Web層框架對網站中所有異常的統一處理

配置文件 數據安全 攔截器 網站 如何 一個網站的異常信息作為專業的人士,是不會輕易暴露給用戶的,因為那樣狠不安全,顯得你漏是一回事,只要還是考慮到網站的數據安全問題,下面給大家分享一下一些常見的web層框架是如何處理統一的異常。   之前都是在Struts2的配置文件中配置攔截器

日誌中文亂碼處理請求亂碼,響應亂碼,保存數據到數據庫亂碼

conf 服務器 過濾器 close 發布服務 setting open odi idea 1.日誌亂碼處理 中文亂碼需要修改四個部分:1.idea安裝目錄下的bin/idea64.exe.vmoptions和bin/idea.exe.vmoptions追加-Dfile.e

處理nginx訪問日誌,篩選時間大於1秒的請求

nes ash code lse pytho == one num 訪問 #!/usr/bin/env python ‘‘‘ 處理訪問日誌,篩選時間大於1秒的請求 ‘‘‘ with open(‘test.log‘,‘a+‘,encoding=‘utf-8‘) as f_a

jQuery ajax預處理 和後置處理;專案中ajax自動設定 token 請求頭, 介面響應code的統一處理

專案中經常會遇到需要統一設定 ajax請求的預處理 和 需要統一處理ajax返回的需求 比如登入時需要 在頭部新增token(X-Auth-Token) 請求完需要判斷code為已退出token失效(3001)和許可權不足(3002)的情況 開始使

WEB 請求處理 一:瀏覽器 請求發起處理

最近,終於要把《WEB請求處理系列》提上日程了,一直答應小夥伴們給分享一套完整的WEB請求處理流程:從瀏覽器、Nginx、Servlet容器,最終到應用程式WEB請求的一個處理流程,前段時間由於其他工作事情的安排,一直未進行整理。不過還好該系列終於啟動了,給大家分享的同時,也順便整理下自己的思路,以