SpringBoot統計接口調用耗時的三種方式
引言
在實際開發(fā)中,了解項目中接口的響應時間是必不可少的事情。SpringBoot 項目支持監(jiān)聽接口的功能也不止一個,接下來我們分別以 AOP、ApplicationListener、Tomcat 三個方面去實現三種不同的監(jiān)聽接口響應時間的操作。
AOP
首先我們在項目中創(chuàng)建一個類 ,比如就叫 WebLogAspect ,然后在該類上加上 @Aspect 和 @Component 注解,聲明是一個 Bean 并且是一個切面:
import org.aspectj.lang.JoinPoint; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.*; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Component; import org.springframework.web.context.request.RequestContextHolder; import org.springframework.web.context.request.ServletRequestAttributes; import javax.servlet.http.HttpServletRequest; import java.util.Date; @Aspect @Component public class WebLogAspect { private static final Logger logger = LoggerFactory.getLogger(WebLogAspect.class); // 定義一個切入點,攔截所有帶有@RequestMapping注解的方法 @Pointcut("@annotation(org.springframework.web.bind.annotation.RequestMapping)") public void webLog() {} // 前置通知,在方法執(zhí)行前記錄請求信息 @Before("webLog()") public void doBefore(JoinPoint joinPoint) { ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes(); HttpServletRequest request = attributes.getRequest(); // 記錄請求信息 logger.info("請求開始:URL={}, IP={}, 方法={}", request.getRequestURL(), request.getRemoteAddr(), request.getMethod()); } // 環(huán)繞通知,記錄方法執(zhí)行時間 @Around("webLog()") public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable { long startTime = System.currentTimeMillis(); Object result = joinPoint.proceed(); // 繼續(xù)執(zhí)行被攔截的方法 long endTime = System.currentTimeMillis(); long executeTime = endTime - startTime; // 記錄執(zhí)行時間 logger.info("請求結束:耗時={}ms", executeTime); return result; } // 異常通知,在方法拋出異常時記錄異常信息 @AfterThrowing(pointcut = "webLog()", throwing = "ex") public void doAfterThrowing(JoinPoint joinPoint, Exception ex) { ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes(); HttpServletRequest request = attributes.getRequest(); // 記錄異常信息 logger.error("請求異常:URL={}, 異常={}", request.getRequestURL(), ex.getMessage()); } // 后置通知(返回通知),在方法正常返回后記錄信息 @AfterReturning(returning = "retVal", pointcut = "webLog()") public void doAfterReturning(JoinPoint joinPoint, Object retVal) { // 你可以在這里記錄返回值,但通常我們不記錄,因為可能會包含敏感信息 // logger.info("請求返回:返回值={}", retVal); } }
2024-06-19 17:49:37.373 [TID: N/A] WARN [com.springboot.demo.TakeTimeCountListener] 請求開始:URL=http://localhost:18080/springboot/test1, IP=0:0:0:0:0:0:0:1, 方法=POST
2024-06-19 17:49:37.386 [TID: N/A] WARN [com.springboot.demo.TakeTimeCountListener] 請求結束:耗時=13ms
2024-06-19 17:49:37.501 [TID: N/A] WARN [com.springboot.demo.TakeTimeCountListener] 請求開始:URL=http://localhost:18080/springboot/test2, IP=0:0:0:0:0:0:0:1, 方法=POST
2024-06-19 17:49:37.516 [TID: N/A] WARN [com.springboot.demo.TakeTimeCountListener] 請求結束:耗時=15ms
2024-06-19 17:49:37.905 [TID: N/A] WARN [com.springboot.demo.TakeTimeCountListener] 請求開始:URL=http://localhost:18080/springboot/test3, IP=0:0:0:0:0:0:0:1, 方法=POST
2024-06-19 17:49:37.913 [TID: N/A] WARN [com.springboot.demo.TakeTimeCountListener] 請求結束:耗時=8ms
優(yōu)點:
- 全局性:可以在不修改業(yè)務代碼的情況下,對全局范圍內的接口進行執(zhí)行時間的記錄。
- 靈活性:可以根據需要靈活定義哪些接口需要記錄執(zhí)行時間。
- 精確性:可以精確記錄從方法開始執(zhí)行到結束的時間。
缺點:
- 配置復雜性:AOP配置可能相對復雜,特別是對于初學者來說。
- 性能開銷:雖然性能開銷通常很小,但在高并發(fā)場景下仍然需要考慮,并且它是會阻塞主線程的。
**常用性:**在Spring框架中,AOP是一個強大的工具,用于實現諸如日志記錄、事務管理等橫切關注點。因此,使用AOP記錄接口執(zhí)行時間是一種非常常見和推薦的做法。
ApplicationListener
首先我們在項目中創(chuàng)建一個類 ,比如就叫 TakeTimeCountListener,然后實現 ApplicationListener 接口:
import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.context.ApplicationListener; import org.springframework.stereotype.Component; import org.springframework.web.context.support.ServletRequestHandledEvent; @Component public class TakeTimeCountListener implements ApplicationListener<ServletRequestHandledEvent> { public final Logger logger = LoggerFactory.getLogger(this.getClass()); @Override public void onApplicationEvent(ServletRequestHandledEvent event) { Throwable failureCause = event.getFailureCause() ; if (failureCause != null) { logger.warn("錯誤原因: {}", failureCause.getMessage()); } // 比如我這里只記錄接口響應時間大于1秒的日志 if (event.getProcessingTimeMillis() > 1000) { logger.warn("請求客戶端地址:{}, 請求URL: {}, 請求Method: {}, 請求耗時:{} ms", event.getClientAddress(), event.getRequestUrl(), event.getMethod(), event.getProcessingTimeMillis()); } } }
2024-06-19 17:14:59.620 [TID: N/A] WARN [com.springboot.demo.TakeTimeCountListener] 請求客戶端地址:0:0:0:0:0:0:0:1, 請求URL: /springboot/test1, 請求Method: GET, 請求耗時:51 ms
2024-06-19 17:14:59.716 [TID: N/A] WARN [com.springboot.demo.TakeTimeCountListener] 請求客戶端地址:0:0:0:0:0:0:0:1, 請求URL: /springboot/test2, 請求Method: GET, 請求耗時:136 ms
2024-06-19 17:14:59.787 [TID: N/A] WARN [com.springboot.demo.TakeTimeCountListener] 請求客戶端地址:0:0:0:0:0:0:0:1, 請求URL: /springboot/test3, 請求Method: POST, 請求耗時:255 ms
2024-06-19 17:14:59.859 [TID: N/A] WARN [com.springboot.demo.TakeTimeCountListener] 請求客戶端地址:0:0:0:0:0:0:0:1, 請求URL: /springboot/test4, 請求Method: POST, 請求耗時:167 ms
優(yōu)點:
- 集成性:與Spring MVC框架緊密集成,無需額外配置。
- 性能:改方法是不會阻塞主線程的,也就是說 該方法在處理的時候,controller 已經正常返回了,可以通過在該方法進行斷點調試來驗證。
- 簡單易用:實現ApplicationListener接口并監(jiān)聽ServletRequestHandledEvent事件即可。
缺點:
- 適用范圍:主要適用于Spring MVC 框架下的 Web 請求,對于非 Web 接口(如RESTful API)可能不適用。
- 精度:只能記錄整個請求的處理時間,無法精確到具體的方法執(zhí)行時間。
**常用性:**在Spring MVC應用中,使用ApplicationListener來記錄請求處理時間是一種常見做法,但通常用于監(jiān)控和性能分析,而不是精確記錄接口執(zhí)行時間。
Tomcat
Tomcat 的實現很簡單,只需要開啟它本身就支持的訪問日志就可以了 ,在 SpringBoot 中,我們可以在 properties 或 yaml 文件中增加下面配置:
# 啟用Tomcat訪問日志 server.tomcat.accesslog.enabled=true # 啟用緩沖模式,日志會先寫入緩沖區(qū),然后定期刷新到磁盤 server.tomcat.accesslog.buffered=true # 指定日志存儲目錄,這里是相對于項目根目錄的logs文件夾 server.tomcat.accesslog.directory=logs # 定義日志文件名的日期格式 server.tomcat.accesslog.file-date-format=.yyyy-MM-dd # 定義日志記錄的格式 # 各個字段的意義: # %{X-Forwarded-For}i: 請求頭中的X-Forwarded-For,通常用于記錄客戶端真實IP # %p: 本地端口 # %l: 遠程用戶,通常為'-' # %r: 請求的第一行(例如:GET / HTTP/1.1) # %t: 請求時間(格式由日志處理器決定) # 注意:這里有一個重復的%r,可能是個錯誤,通常第二個%r不需要 # %s: HTTP狀態(tài)碼 # %b: 響應字節(jié)數,不包括HTTP頭,如果為0則不輸出 # %T: 請求處理時間(以秒為單位) server.tomcat.accesslog.pattern=%{X-Forwarded-For}i %p %l %r %t %r %s %b %T # 日志文件名前綴 server.tomcat.accesslog.prefix=localhost_access_log # 日志文件名后綴 server.tomcat.accesslog.suffix=.log
server: tomcat: accesslog: enabled: true # 啟用Tomcat訪問日志 buffered: true # 啟用緩沖模式,日志會先寫入緩沖區(qū),然后定期刷新到磁盤 directory: logs # 指定日志存儲目錄,這里是相對于項目根目錄的logs文件夾 file-date-format: ".yyyy-MM-dd" # 定義日志文件名的日期格式 pattern: "%{X-Forwarded-For}i %p %l %r %t %s %b %T" # 定義日志記錄的格式 prefix: localhost_access_log # 日志文件名前綴 suffix: .log # 日志文件名后綴
- 8080 - - [19/Jun/2024:00:00:09 +0800] GET /springboot/test1 HTTP/1.1 200 92 0.247 Ignored_Trace
- 8080 - - [19/Jun/2024:00:00:09 +0800] GET /springboot/test2 HTTP/1.1 200 92 0.247 Ignored_Trace
- 8080 - - [19/Jun/2024:09:49:55 +0800] POST /springboot/test3 HTTP/1.1 200 291556 0.314 Ignored_Trace
優(yōu)點:
- 集成性:Tomcat 內置功能,無需額外代碼或配置。
- 全面性:記錄所有通過 Tomcat 處理的請求和響應信息。
缺點:
- 性能:訪問日志可能會對 Tomcat 性能產生一定影響。
- 精度:同樣只能記錄整個請求的處理時間,無法精確到具體的方法執(zhí)行時間。
- 配置復雜性:對于復雜的日志格式或需求,可能需要修改 Tomcat 的配置文件。
**常用性:**Tomcat 的訪問日志通常用于監(jiān)控 Web 服務器的訪問情況,如 IP 地址、請求路徑、HTTP 狀態(tài)碼等。雖然它可以記錄請求處理時間,但通常不會用于精確的性能分析或接口執(zhí)行時間記錄。
以上就是SpringBoot統計接口調用耗時的三種方式的詳細內容,更多關于SpringBoot統計接口耗時的資料請關注腳本之家其它相關文章!
相關文章
Spring Cloud Hystrix 線程池隊列配置(踩坑)
這篇文章主要介紹了Spring Cloud Hystrix 線程池隊列配置(踩坑),小編覺得挺不錯的,現在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2019-01-01rabbitmq的消息持久化處理開啟,再關閉后,消費者啟動報錯問題
這篇文章主要介紹了rabbitmq的消息持久化處理開啟,再關閉后,消費者啟動報錯問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2023-11-11