springboot基于过滤器实现接口请求耗时统计操作

 更新时间:2020年09月26日 09:58:40   作者:ye17186  
这篇文章主要介绍了springboot基于过滤器实现接口请求耗时统计操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧

Spring Boot中实现一个过滤器相当简单,实现javax.servlet.Filter接口即可。

下面以实现一个记录接口访问日志及请求耗时的过滤器为例:

1、定义ApiAccessFilter类,并实现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(); // 请求ID,这个是我业务中的id,大家可自行决定是否需要
    long start = System.currentTimeMillis(); // 请求进入时间
 
    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 请求
   * @return request发起客户端的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)) {
      //多次反向代理后会有多个ip值,第一个ip才是真实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、启用该过滤器

springboot中两种启用过滤器的方式,第一种在FilterRegistrationBean中注册该Filter,第二种,采用注解的方式启用

个人觉得注册方式比较麻烦,所有本例中使用的是第二种。

在Filter中添加注解@WebFilter(filterName = "ApiAccessFilter", urlPatterns = "/*"),配置了过滤器名和需要过滤的请求地址,/*表示过滤所有请求。然后在启动类上,通过@ServletComponentScan注解,指明该过滤器即可

@SpringBootApplication
@ServletComponentScan("com.yclouds.service.demo")
public class YCloudsServiceDemoApplication {
 
  public static void main(String[] args) {
    SpringApplication.run(YCloudsServiceDemoApplication.class, args);
  }
}

3、效果展示

发送了两次http请求,每次都会打印日志内容,并且统计了整个请求的耗时情况。

GitHub地址:https://github.com/ye17186/spring-boot-learn

补充知识:spring cloud gateway 之zuul通过filter配置接口请求的时间耗时记录到日志

zuul中的Filter的配置,zuul中提供了三种类型的Filter,preFilter,routeFilter和postFilter,分别对应请求中的不同的阶段,针对同一个请求,有一个RequestContext对象,在三个阶段的Filter中进行共享

假设我们要开发一个统计请求时间的功能,需要在preFilter里边记录开始时间,并将整个开始时间放在RequestContext中,在postFilter里边拿到开始时间,用当前的时间减去开始时间,就是请求执行的时间

定义一个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("请求完成,耗时{}秒", (System.currentTimeMillis() - startTime) / 1000);
    return null;
  }
}

在一个配置类中将这两个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();
  }
}

启动项目,可以发现,zuul网关已经注册到了eureka上:

请求provide对应的地址,发现,zuul可以成功地调用eureka上对应的服务,并将结果正确返回:

以上这篇springboot基于过滤器实现接口请求耗时统计操作就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持脚本之家。

相关文章

  • 微信APP支付Java代码

    微信APP支付Java代码

    这篇文章主要为大家详细介绍了微信APP支付Java代码,感兴趣的小伙伴们可以参考一下
    2016-07-07
  • Eclipse创建java程序可执行jar包教程

    Eclipse创建java程序可执行jar包教程

    这篇文章主要为大家分享了Eclipse创建java程序可执行jar包教程,具有一定的实用性和参考价值,感兴趣的小伙伴们可以参考一下
    2016-05-05
  • Java使用线程实现异步运行的方法

    Java使用线程实现异步运行的方法

    在Java中,实现异步运行的一个常用方式是使用Thread类,这篇文章主要介绍了Java使用线程实现异步运行,需要的朋友可以参考下
    2024-07-07
  • Java中的深拷贝和浅拷贝介绍

    Java中的深拷贝和浅拷贝介绍

    对象拷贝(Object Copy)就是将一个对象的属性拷贝到另一个有着相同类类型的对象中去。在程序中拷贝对象是很常见的,主要是为了在新的上下文环境中复用对象的部分或全部 数据。Java中有三种类型的对象拷贝:浅拷贝(Shallow Copy)、深拷贝(Deep Copy)、延迟拷贝(Lazy Copy)
    2014-03-03
  • Java的Spring AOP详细讲解

    Java的Spring AOP详细讲解

    章主要为大家详细介绍了Java的Spring AOP,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下,希望能够给你带来帮助
    2022-02-02
  • 新版SpringSecurity5.x使用与配置详解

    新版SpringSecurity5.x使用与配置详解

    Spring Security是一个强大且高度可定制的身份验证和访问控制框架,本文主要介绍了新版SpringSecurity5.x使用与配置详解,具有一定的参考价值,感兴趣的可以了解一下
    2024-08-08
  • 一文盘点五种最常用的Java加密算法

    一文盘点五种最常用的Java加密算法

    大家平时的工作中,可能也在很多地方用到了加密、解密,比如:支付功能等,所以本文为大家盘点了Java中五个常用的加密算法,希望对大家有所帮助
    2023-06-06
  • Java学习教程之定时任务全家桶

    Java学习教程之定时任务全家桶

    这篇文章主要给大家介绍了关于Java学习教程之定时任务全家桶的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-11-11
  • Java this、final等关键字总结

    Java this、final等关键字总结

    这篇文章主要对java中this、final等关键字进行了总结,需要的朋友可以参考下
    2017-04-04
  • java实现弹球小游戏

    java实现弹球小游戏

    这篇文章主要为大家详细介绍了java实现弹球小游戏,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-06-06

最新评论