springboot基于過(guò)濾器實(shí)現(xiàn)接口請(qǐng)求耗時(shí)統(tǒng)計(jì)操作
Spring Boot中實(shí)現(xiàn)一個(gè)過(guò)濾器相當(dāng)簡(jiǎn)單,實(shí)現(xiàn)javax.servlet.Filter接口即可。
下面以實(shí)現(xiàn)一個(gè)記錄接口訪問(wèn)日志及請(qǐng)求耗時(shí)的過(guò)濾器為例:
1、定義ApiAccessFilter類,并實(shí)現(xiàn)Filter接口
@Slf4j
@WebFilter(filterName = "ApiAccessFilter", urlPatterns = "/*")
public class ApiAccessFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) {
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse,
FilterChain filterChain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) servletRequest;
Long requestId = IdGenUtils.nextIdByMem(); // 請(qǐng)求ID,這個(gè)是我業(yè)務(wù)中的id,大家可自行決定是否需要
long start = System.currentTimeMillis(); // 請(qǐng)求進(jìn)入時(shí)間
log.info("[Api Access] start. id: {}, uri: {}, method: {}, client: {}", requestId,
request.getRequestURI(), request.getMethod(), getIP(request));
filterChain.doFilter(servletRequest, servletResponse);
log.info("[Api Access] end. id: {}, duration: {}ms", requestId,
System.currentTimeMillis() - start);
}
@Override
public void destroy() {
}
/**
* 獲取IP地址
*
* @param request 請(qǐng)求
* @return request發(fā)起客戶端的IP地址
*/
private String getIP(HttpServletRequest request) {
if (request == null) {
return "0.0.0.0";
}
String Xip = request.getHeader("X-Real-IP");
String XFor = request.getHeader("X-Forwarded-For");
String UNKNOWN_IP = "unknown";
if (StringUtils.isNotEmpty(XFor) && !UNKNOWN_IP.equalsIgnoreCase(XFor)) {
//多次反向代理后會(huì)有多個(gè)ip值,第一個(gè)ip才是真實(shí)ip
int index = XFor.indexOf(",");
if (index != -1) {
return XFor.substring(0, index);
} else {
return XFor;
}
}
XFor = Xip;
if (StringUtils.isNotEmpty(XFor) && !UNKNOWN_IP.equalsIgnoreCase(XFor)) {
return XFor;
}
if (StringUtils.isBlank(XFor) || UNKNOWN_IP.equalsIgnoreCase(XFor)) {
XFor = request.getHeader("Proxy-Client-IP");
}
if (StringUtils.isBlank(XFor) || UNKNOWN_IP.equalsIgnoreCase(XFor)) {
XFor = request.getHeader("WL-Proxy-Client-IP");
}
if (StringUtils.isBlank(XFor) || UNKNOWN_IP.equalsIgnoreCase(XFor)) {
XFor = request.getHeader("HTTP_CLIENT_IP");
}
if (StringUtils.isBlank(XFor) || UNKNOWN_IP.equalsIgnoreCase(XFor)) {
XFor = request.getHeader("HTTP_X_FORWARDED_FOR");
}
if (StringUtils.isBlank(XFor) || UNKNOWN_IP.equalsIgnoreCase(XFor)) {
XFor = request.getRemoteAddr();
}
return XFor;
}
}
2、啟用該過(guò)濾器
springboot中兩種啟用過(guò)濾器的方式,第一種在FilterRegistrationBean中注冊(cè)該Filter,第二種,采用注解的方式啟用
個(gè)人覺(jué)得注冊(cè)方式比較麻煩,所有本例中使用的是第二種。
在Filter中添加注解@WebFilter(filterName = "ApiAccessFilter", urlPatterns = "/*"),配置了過(guò)濾器名和需要過(guò)濾的請(qǐng)求地址,/*表示過(guò)濾所有請(qǐng)求。然后在啟動(dòng)類上,通過(guò)@ServletComponentScan注解,指明該過(guò)濾器即可
@SpringBootApplication
@ServletComponentScan("com.yclouds.service.demo")
public class YCloudsServiceDemoApplication {
public static void main(String[] args) {
SpringApplication.run(YCloudsServiceDemoApplication.class, args);
}
}
3、效果展示

發(fā)送了兩次http請(qǐng)求,每次都會(huì)打印日志內(nèi)容,并且統(tǒng)計(jì)了整個(gè)請(qǐng)求的耗時(shí)情況。
GitHub地址:https://github.com/ye17186/spring-boot-learn
補(bǔ)充知識(shí):spring cloud gateway 之zuul通過(guò)filter配置接口請(qǐng)求的時(shí)間耗時(shí)記錄到日志
zuul中的Filter的配置,zuul中提供了三種類型的Filter,preFilter,routeFilter和postFilter,分別對(duì)應(yīng)請(qǐng)求中的不同的階段,針對(duì)同一個(gè)請(qǐng)求,有一個(gè)RequestContext對(duì)象,在三個(gè)階段的Filter中進(jìn)行共享

假設(shè)我們要開(kāi)發(fā)一個(gè)統(tǒng)計(jì)請(qǐng)求時(shí)間的功能,需要在preFilter里邊記錄開(kāi)始時(shí)間,并將整個(gè)開(kāi)始時(shí)間放在RequestContext中,在postFilter里邊拿到開(kāi)始時(shí)間,用當(dāng)前的時(shí)間減去開(kāi)始時(shí)間,就是請(qǐng)求執(zhí)行的時(shí)間
定義一個(gè)preFilter:
package com.jiaoyiping.springcloud.zuul.filter;
import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import com.netflix.zuul.exception.ZuulException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.cloud.netflix.zuul.filters.support.FilterConstants;
/**
* Created with Intellij IDEA
*
* @author:
* Mail:
* Date:
* Time:
* To change this template use File | Settings | Editor | File and Code Templates
*/
public class TimeCostPreFilter extends ZuulFilter {
public static final String START_TIME_KEY = "start_time";
private Logger logger = LoggerFactory.getLogger(TimeCostPreFilter.class);
@Override
public String filterType() {
return FilterConstants.PRE_TYPE;
}
@Override
public int filterOrder() {
return 0;
}
/**
* 判斷是否要攔截的邏輯
*
* @return
*/
@Override
public boolean shouldFilter() {
return true;
}
@Override
public Object run() throws ZuulException {
long startTime = System.currentTimeMillis();
RequestContext.getCurrentContext().set(START_TIME_KEY, startTime);
return null;
}
}
定義以postFilter:
package com.jiaoyiping.springcloud.zuul.filter;
import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import com.netflix.zuul.exception.ZuulException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.cloud.netflix.zuul.filters.support.FilterConstants;
/**
* Created with Intellij IDEA
*
* @author:
* Mail:
* Date:
* Time:
* To change this template use File | Settings | Editor | File and Code Templates
*/
public class TimeCostPostFilter extends ZuulFilter {
private static final String START_TIME_KE = "start_time";
private Logger logger = LoggerFactory.getLogger(TimeCostPostFilter.class);
@Override
public String filterType() {
return FilterConstants.POST_TYPE;
}
@Override
public int filterOrder() {
return 0;
}
@Override
public boolean shouldFilter() {
return true;
}
@Override
public Object run() throws ZuulException {
long startTime = (long) RequestContext.getCurrentContext().get(START_TIME_KE);
logger.info("請(qǐng)求完成,耗時(shí){}秒", (System.currentTimeMillis() - startTime) / 1000);
return null;
}
}
在一個(gè)配置類中將這兩個(gè)Filter注入:
package com.jiaoyiping.springcloud.zuul.config;
import com.jiaoyiping.springcloud.zuul.filter.PDSFilter;
import com.jiaoyiping.springcloud.zuul.filter.TimeCostPostFilter;
import com.jiaoyiping.springcloud.zuul.filter.TimeCostPreFilter;
import com.netflix.zuul.ZuulFilter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* Created with Intellij IDEA
*
* @author:
* Mail:
* Date:
* Time:
* To change this template use File | Settings | Editor | File and Code Templates
*/
@Configuration
public class FilterConfig {
@Bean
public ZuulFilter timeCostPreFilter() {
return new TimeCostPreFilter();
}
@Bean
public ZuulFilter timeCostPostFilter() {
return new TimeCostPostFilter();
}
@Bean
public ZuulFilter pdsFilter() {
return new PDSFilter();
}
}
啟動(dòng)項(xiàng)目,可以發(fā)現(xiàn),zuul網(wǎng)關(guān)已經(jīng)注冊(cè)到了eureka上:

請(qǐng)求provide對(duì)應(yīng)的地址,發(fā)現(xiàn),zuul可以成功地調(diào)用eureka上對(duì)應(yīng)的服務(wù),并將結(jié)果正確返回:

以上這篇springboot基于過(guò)濾器實(shí)現(xiàn)接口請(qǐng)求耗時(shí)統(tǒng)計(jì)操作就是小編分享給大家的全部?jī)?nèi)容了,希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
- SpringBoot中統(tǒng)計(jì)方法耗時(shí)的七種實(shí)現(xiàn)方式小結(jié)
- SpringBoot統(tǒng)計(jì)接口請(qǐng)求耗時(shí)的方法詳解
- SpringBoot統(tǒng)計(jì)接口調(diào)用耗時(shí)的三種方式
- Springboot之如何統(tǒng)計(jì)代碼執(zhí)行耗時(shí)時(shí)間
- Spring?Boot源碼實(shí)現(xiàn)StopWatch優(yōu)雅統(tǒng)計(jì)耗時(shí)
- SpringBoot中的7種耗時(shí)統(tǒng)計(jì)的實(shí)現(xiàn)方法與應(yīng)用場(chǎng)景
相關(guān)文章
教你怎么用Java通過(guò)關(guān)鍵字修改pdf
此方法只適合通過(guò)關(guān)鍵字位置,在pdf上添加字符直接上代碼,代碼比較長(zhǎng),大部分自己的理解都在代碼注釋中了,需要的朋友可以參考下2021-05-05
SpringBoot整合mybatis常見(jiàn)問(wèn)題(小結(jié))
這篇文章主要介紹了SpringBoot整合mybatis常見(jiàn)問(wèn)題(小結(jié)),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-12-12
Java中excel表數(shù)據(jù)的批量導(dǎo)入方法
這篇文章主要為大家詳細(xì)介紹了Java中excel表數(shù)據(jù)的批量導(dǎo)入方法,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-05-05
詳解Java的call by value和call by reference
在本篇文章里小編給大家總結(jié)了關(guān)于Java的call by value和call by reference的相關(guān)用法和知識(shí)點(diǎn)內(nèi)容,需要的朋友們學(xué)習(xí)下。2019-03-03
java判斷用戶輸入的是否至少含有N位小數(shù)的實(shí)例
下面小編就為大家分享一篇java判斷用戶輸入的是否至少含有N位小數(shù)的實(shí)例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2017-12-12
idea中Maven鏡像源詳細(xì)配置步驟記錄(對(duì)所有項(xiàng)目)
Maven是一個(gè)能使我們的java程序開(kāi)發(fā)節(jié)省時(shí)間和精力,是開(kāi)發(fā)變得相對(duì)簡(jiǎn)單,還能使開(kāi)發(fā)規(guī)范化的工具,下面這篇文章主要給大家介紹了關(guān)于idea中Maven鏡像源詳細(xì)配置(對(duì)所有項(xiàng)目)的相關(guān)資料,需要的朋友可以參考下2023-05-05
Java異常報(bào)錯(cuò):java.nio.file.FileSystemException的多種解決方案
在Java應(yīng)用程序中處理文件和目錄時(shí),java.nio.file.FileSystemException是一個(gè)常見(jiàn)的異常,這個(gè)異常發(fā)生在嘗試進(jìn)行文件系統(tǒng)操作時(shí),本文將詳細(xì)探討FileSystemException的成因,并提供多種解決方案,需要的朋友可以參考下2024-12-12
使用Java的方式模擬Flutter的Widget實(shí)現(xiàn)多層括號(hào)嵌套
這篇文章主要介紹了使用Java的方式模擬Flutter的Widget的實(shí)現(xiàn)多層括號(hào)嵌套問(wèn)題,本文給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2019-07-07
Spring?Boot?整合?Reactor實(shí)例詳解
這篇文章主要為大家介紹了Spring?Boot?整合?Reactor實(shí)例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-09-09

