背景
CatFilter是用于http监控,即web项目里的controller类里的方法的监控。
实现原理其实就是servlet里的filter。
本文主要讲springboot web项目和非springboot web项目如何实现监控url监控。
CatFilter
是cat客户端jar里的类,实现了servlet里的Filter接口。
非springboot web项目
直接配置即可,配置filter之后,就相当于引入了过滤器,这个和servlet filter的使用方法一样。
web.xml
<!-- cat监控http请求-->
<filter>
<filter-name>cat-filter</filter-name>
<filter-class>com.dianping.cat.servlet.CatFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>cat-filter</filter-name>
<url-pattern>*.do</url-pattern>
</filter-mapping>
springboob web项目
如果是拦截所有请求,就直接用cat自带的CatFilter即可。
但是如果要排除静态资源,就需要扩展CatFilter,因为springboot filter不支持排除资源路径,只支持pattern匹配。
扩展CatFilter
package com.xxx.qrcode.ugate.payment.filter;
import com.dianping.cat.servlet.CatFilter;
import java.io.IOException;
import java.util.Arrays;
import java.util.List;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import org.springframework.util.AntPathMatcher;
/**
* 重写CatFilter,排除.js/.css/.html等静态资源
*
* @author gzh
* @createTime 2021/2/23 2:54 PM
*/
public class QrcodeCatFilter extends CatFilter {
/**
* 排除.js/.css/.html等静态资源
*/
private static List<String> excludeUrlPatterns = Arrays.asList("/**/*.html", "/**/*.jsp",
"/**/*.css", "/**/*.js", "/**/*.png", "/**/*.jpg",
"/**/*.jpeg", "/**/*.gif", "/**/*.svg");
private static AntPathMatcher antPathMatcher = new AntPathMatcher();
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
//获取当前请求的相对路径(即去掉域名/项目名字之后的路径)
HttpServletRequest httpServletRequest = (HttpServletRequest)request;
String ServletPath = httpServletRequest.getServletPath();
//校验路径是否匹配
boolean b = excludeUrlPatterns.stream()
.anyMatch(e -> antPathMatcher.match(e, ServletPath));
if (b) { //如果是静态资源,不走CatFilter
chain.doFilter(request, response);
}else { //如果不是静态资源,才走CatFilter
super.doFilter(request, response, chain);
}
}
}
说明
1.自定义扩展类,覆盖了拦截方法doFilter,会根据是否是静态资源请求路径,来决定要不要被拦截。
2.启动的时候,CatFilter的init等方法,还是会被执行,因为自定义的扩展类继承了CatFilter。
配置过滤器
配置过滤器
/**
* 配置过滤器
* @return
*/
@Bean
public FilterRegistrationBean registerFilter() {
FilterRegistrationBean registration = new FilterRegistrationBean();
registration.setFilter(new QrcodeCatFilter());
// registration.addUrlPatterns("*.do");
// registration.addInitParameter("exclusions", "*.css");
// registration.setName("CatFilter");
return registration;
}
完整配置
package com.xxx.xxx.ugate.payment.config.webconfig;
import com.xxx.qrcode.ugate.payment.filter.QrcodeCatFilter;
import com.xxx.qrcode.ugate.payment.intercepter.LogPreInterceptor;
import xxx.log.logback.web.LogbackConfigListener;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.boot.web.servlet.ServletListenerRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
/**
* LogbackConfigListener配置
* 输出日志文件
*/
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Bean
public ServletListenerRegistrationBean<LogbackConfigListener> initLogbackConfigListener() {
ServletListenerRegistrationBean<LogbackConfigListener> result = new ServletListenerRegistrationBean<>();
result.setListener(new LogbackConfigListener());
return result;
}
/**
* 配置拦截器
* @param registry
*/
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new LogPreInterceptor())
// .addPathPatterns("/**/*.do")
.excludePathPatterns("/**/*.html", "/**/*.jsp",
"/**/*.css", "/**/*.js", "/**/*.png", "/**/*.jpg",
"/**/*.jpeg", "/**/*.gif", "/**/*.svg");
}
/**
* 配置过滤器
* @return
*/
@Bean
public FilterRegistrationBean registerFilter() {
FilterRegistrationBean registration = new FilterRegistrationBean();
registration.setFilter(new QrcodeCatFilter());
// registration.addUrlPatterns("*.do");
// registration.addInitParameter("exclusions", "*.css");
// registration.setName("CatFilter");
return registration;
}
}
参考
https://github.com/spring-pro...
jdk8知识点
如何排除静态资源请求路径?
自定义扩展过滤器的源码
package com.xxx.qrcode.ugate.payment.filter;
import com.dianping.cat.servlet.CatFilter;
import java.io.IOException;
import java.util.Arrays;
import java.util.List;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import org.springframework.util.AntPathMatcher;
/**
* 重写CatFilter,排除.js/.css/.html等静态资源
*
* @author gzh
* @createTime 2021/2/23 2:54 PM
*/
public class QrcodeCatFilter extends CatFilter {
/**
* 排除.js/.css/.html等静态资源
*/
private static List<String> excludeUrlPatterns = Arrays.asList("/**/*.html", "/**/*.jsp",
"/**/*.css", "/**/*.js", "/**/*.png", "/**/*.jpg",
"/**/*.jpeg", "/**/*.gif", "/**/*.svg");
private static AntPathMatcher antPathMatcher = new AntPathMatcher();
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
//获取当前请求的相对路径(即去掉域名/项目名字之后的路径)
HttpServletRequest httpServletRequest = (HttpServletRequest)request;
String ServletPath = httpServletRequest.getServletPath();
//校验路径是否匹配
boolean b = excludeUrlPatterns.stream()
.anyMatch(e -> antPathMatcher.match(e, ServletPath));
if (b) { //如果是静态资源,不走CatFilter
chain.doFilter(request, response);
}else { //如果不是静态资源,才走CatFilter
super.doFilter(request, response, chain);
}
}
}
排除静态资源的时候,用了jdk8的知识点。
1.得到流stream
主要是从集合得到流,这个是jdk8才有的功能和方法。
2.得到流之后,要对流数据进行计算
什么计算?匹配数据。怎么匹配?用anyMatch方法来匹配。
3.anyMatch方法的入参是Predicate类型
源码
public interface Stream<T> extends BaseStream<T, Stream<T>> {
/**
* Returns whether any elements of this stream match the provided
* predicate. May not evaluate the predicate on all elements if not
* necessary for determining the result. If the stream is empty then
* {@code false} is returned and the predicate is not evaluated.
*
* <p>This is a <a href="package-summary.html#StreamOps">short-circuiting
* terminal operation</a>.
*
* @apiNote
* This method evaluates the <em>existential quantification</em> of the
* predicate over the elements of the stream (for some x P(x)).
*
* @param predicate a <a href="package-summary.html#NonInterference">non-interfering</a>,
* <a href="package-summary.html#Statelessness">stateless</a>
* predicate to apply to elements of this stream
* @return {@code true} if any elements of the stream match the provided
* predicate, otherwise {@code false}
*/
boolean anyMatch(Predicate<? super T> predicate);
Predicate类型是函数式接口
/**
* Represents a predicate (boolean-valued function) of one argument.
*
* <p>This is a <a href="package-summary.html">functional interface</a>
* whose functional method is {@link #test(Object)}.
*
* @param <T> the type of the input to the predicate
*
* @since 1.8
*/
@FunctionalInterface //有函数式接口注解,说明就是函数式接口,即入参可以是lambda表达式语句或代码块
public interface Predicate<T> {
4.e是什么?
e是遍历流的时候,流里的当前元素。
5.AntPathMatcher
pattern模式匹配路径,spring框架自带的匹配路径功能。核心有两点:
1)*.do
*,表示匹配0或多个字符
2)/**
/**,表示匹配0或多个目录
参考
jdk8实战
总结
除了用Jdk8里的知识点,去排除静态资源请求路径,当然也可以用传统的代码去排除。具体实现就是遍历集合数据,然后一个个数据去匹配当前请求路径。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。