注:Filter可以实现的功能部分也可由Interceptor来实现
Filter和Interceptor区别
Filter能够顺序执行就是因为FilterChain的存在,每一个filter执行filterChain.doFilter()的时候都会把filterChain对象传入,然后交给下一个filter,目的就是保证每一个filter都可以持有filterChain,直到把所有的filter都执行完。在执行完servlet之后还会倒序返回到各个filter中。Filter的生命周期没有特别声明时同servlet一样。
首先debug查看工程的chain,包含的有
YouCan-filter
->httpmonitor-filter
->SetCharacterEncoding
->YouCanCommonFilter
->YouCanApp-filter
->log4j2-filter
->rhinoControl-filter
->set-proxy-filter
->applicationContextIdFilter
->Jetty_WebSocketUpgradeFilter
->dispatcherServlet@7ef5559e==org.springframework.web.servlet.DispatcherServlet,jsp=null,order=-1,inst=true
工程使用的是jetty容器,分析一下jetty中对于Filter的执行处理,
首先是javax.servlet-api中的Filter接口和FilterChain接口
public interface Filter {
public void init(FilterConfig filterConfig) throws ServletException;
/**
* 1.doFilter中都是使用chain.doFilter把执行流交给FilterChain来管理;doFilter之前的部分都是处理之前的过滤操作,之后的部分都是处理之后的过滤操作
* 2.自定义Filter中重点关注的部分就是doFilter方法,关乎了过滤的意义
*/
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain)
throws IOException, ServletException;
public void destroy();
}
public interface FilterChain {
public void doFilter ( ServletRequest request, ServletResponse response ) throws IOException, ServletException;
}
接着是Jetty中的CacheChain,springBoot使用了jetty容器(默认tomcat),因此FilterChain是由它来实现的
protected class CachedChain implements FilterChain {
// 当前filter的持有者
FilterHolder _filterHolder;
// 指向下一个filter,没有则为null
ServletHandler.CachedChain _next;
// servlet处理的持有者
ServletHolder _servletHolder;
protected CachedChain(List<FilterHolder> filters, ServletHolder servletHolder) {
// 初始化的时候就递归确认各filter的holder
if (filters.size() > 0) {
this._filterHolder = (FilterHolder)filters.get(0);
filters.remove(0);
this._next = ServletHandler.this.new CachedChain(filters, servletHolder);
} else {
// 初始化时没有filter则直接把执行流交给相应的servlet
this._servletHolder = servletHolder;
}
}
public void doFilter(ServletRequest request, ServletResponse response) throws IOException, ServletException {
Request baseRequest = Request.getBaseRequest(request);
// filterHolder是在Filterchain中每一个filter被轮询时的所有者,当filterHolder为null时,表示chain中的filter都已经被轮询了
if (this._filterHolder != null) {
if (ServletHandler.LOG.isDebugEnabled()) {
ServletHandler.LOG.debug("call filter {}", new Object[]{this._filterHolder});
}
Filter filter = this._filterHolder.getFilter();
// 判断baseRequest是否加锁以及当前filter的执行者是否未加锁
if (baseRequest.isAsyncSupported() && !this._filterHolder.isAsyncSupported()) {
try {
baseRequest.setAsyncSupported(false, this._filterHolder.toString());
// 执行流交给下一个filter执行者
filter.doFilter(request, response, this._next);
} finally {
baseRequest.setAsyncSupported(true, (String)null);
}
} else {
// 执行流交给下一个filter执行者
filter.doFilter(request, response, this._next);
}
} else {
// 执行到此表示所有的filter都已经执行完了,将句柄交给Servlet持有者
HttpServletRequest srequest = (HttpServletRequest)request;
if (this._servletHolder == null) {
ServletHandler.this.notFound(baseRequest, srequest, (HttpServletResponse)response);
} else {
if (ServletHandler.LOG.isDebugEnabled()) {
ServletHandler.LOG.debug("call servlet " + this._servletHolder, new Object[0]);
}
// serletk执行者开始处理请求
this._servletHolder.handle(baseRequest, request, response);
}
}
}
执行方法:
ServletHolder.handle() ->
FrameworkServlet.service() -> FrameworkServlet.processRequest()
DispatcherServlet.doService() -> DispatcherServlet.doDispatch()
执行涉及的类:
Dispatcherervlet -> HandlerExecutionChain -> RequestMappingHandlerAdapter -> ServletInvocableHandlerMethod -> InvocableHandlerMethod
Dispatcherervlet.getHandler()从handlerMappings中遍历找到RequestMappingHandlerMapping,接着在AbstractHandlerMethodMapping根据请求request中的url到合适的HandlerMethod;其中通过获取请求url比对在mappingRegistry存储的工程中相关的url映射找到最满足对比结果的Controller类。后续会获取InterceptorList以便于执行Interceptor中的过滤逻辑。
真正执行Controller中的方法是在InvocableHandlerMethod.invokeForRequest()中的RequestMappingHandlerMapping.doInvoke()中的Bean.invoke()使用反射去执行。
执行的结果放在returnValue中,在返回Handler中找到RequestResponseBodyMethodProcessor,接着一层一层的回调到Interceptor和FilterChain上一层中,直到走完所有的Filter。
在工程中有显示的定义filter的执行优先级,保证想要实现的过滤效果可控的。在加了@Configuration的注解的FilterConfiguration中进行设置。
private static final int TRACE_FILTER_ORDER = 1;
@Bean
public FilterRegistrationBean traceFilter() {
TraceFilter traceFilter = new TraceFilter();
FilterRegistrationBean registration = new FilterRegistrationBean(traceFilter);
registration.addUrlPatterns("/*");
registration.setName("traceFilter");
// 这里设置Filter执行的优先级,数字越小,优先级越高
registration.setOrder(TRACE_FILTER_ORDER);
return registration;
}
但是需要注意的是这里注册的filter优先级并不是真正意义上定义的顺序,debug可以发现在执行traceFilter之前还有SpringBoot自带的一些Filter,它们是Springboot启动依赖的starter自带的一些filter,执行固定配置中的一些默认筛选规则。
如何自定义的Filter执行的优先级要先于框架自带的Filter呢?
在设置filter执行优先级的时候将其设置为
// int HIGHEST_PRECEDENCE = Integer.MIN_VALUE; -2147483648
registration.setOrder(Ordered.HIGHEST_PRECEDENCE);
这样做理论上可以使自定义的Filter是所有Filter中第一个被执行的。为什么是理论上的,是因为这个参数有可能已经被其他Filter设置过了,进行了覆盖。
具体原理是在web容器启动的时候,会调用一个匿名类去加载整个容器内的ServletContetxInitializerBeans,此时所有的filter也会进行加载,接着在for循环中进行排序,其中getOrderedBeansOfType()这个方法就获取到了各个Bean的order,像filter这种Bean就会依赖order去排序加载执行。
private void addServletContextInitializerBeans(ListableBeanFactory beanFactory) {
for (Entry<String, ServletContextInitializer> initializerBean : getOrderedBeansOfType(
beanFactory, ServletContextInitializer.class)) {
addServletContextInitializerBean(initializerBean.getKey(),
initializerBean.getValue(), beanFactory);
}
}