java 过滤器、拦截器
什么是过滤器
过滤器Filter是基于Servlet实现,对进入到Servlet的请求拦截。主要用于对字符编码,跨域等问题过滤。如下图:
所有的请求和都经过Filter,通过定义Filter,能够对请求进行编码操作。代码是以接口的形式提供:
public interface Filter {
default void init(FilterConfig filterConfig) throws ServletException {
}
void doFilter(ServletRequest var1, ServletResponse var2, FilterChain var3) throws IOException, ServletException;
default void destroy() {
}
}
Filter有三个方法init()、doFilter()、destroy()方法
init():web容器启动时,web服务器会创建Filter实例对象,并调用init方法,init在创建Filter创建一次。
destroy():web容器销毁时,会调用该方法,在方法内会销毁资源。
doFilter(): 每一次请求过来,都会被调用,并传递到下一个Filter。如果有配置了URL,即会根据匹配的URL进行选择Filter。最后的Filter会调用具体Servlet执行具体的业务。
配置实例化如下:
// 拦截所有的请求,
@Configuration
public class FilterConfig1 {
@Bean
public FilterRegistrationBean registFilter() {
FilterRegistrationBean registration = new FilterRegistrationBean();
registration.setFilter(new MyFilter());
registration.addUrlPatterns("/*");
registration.setName("PiceaFilter");
registration.addInitParameter("URL","http://localhost:8080");
registration.setOrder(1);
return registration;
}
}
public class MyFilter implements Filter {
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
// 相当于是模拟预设工作
System.out.println("过滤器 这是准备工作.....");
// 放行【如果没有下面的doFilter过程,即为拦截了】,放行后可以到达servlet
chain.doFilter(request, response);
// 相当于是模拟善后工作【servlet工作完后,再回到这里】
System.out.println("过滤器 这是善后工作.....");
}
}
什么是拦截器
同Filter一样,对请求做处理的。也同样使用了AOP的思想,当每个请求,请求到具体的Controller之前,会被拦截。
public interface HandlerInterceptor {
default boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
return true;
}
default void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable ModelAndView modelAndView) throws Exception {
}
default void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable Exception ex) throws Exception {
}
}
preHandle(): 在每个请求处理之前被调用,用来对请求做一些初始化操作,或者是预处理,判断当前请求是否放行。当返回false则立即返回,当返回true时,请求到下一个HandlerInterceptor的preHandle方法,如果是最后一个,则会调用到Controller的具体请求。
postHandle(): 在处理完每个请求后调用
afterCompletion(): 在DispatcherServlet 渲染视图ModelAndView后调用,在之前前后端不分离的情况下,会经常使用,但前后端分离情况下,已经很少使用了。
@Configuration
public class FilterConfig implements WebMvcConfigurer {
/**
* 拦截所有请求,但过滤掉 /login等请求
*/
@Override
public void addInterceptors(InterceptorRegistry registry) {
InterceptorRegistration interceptor = registry.addInterceptor(new LoginFilter());
interceptor.addPathPatterns("/**").excludePathPatterns("/login","/toLogin","/css/**","/js/**","/kaptcha");
}
}
拦截器执行流程如下图:
过滤器和拦截器的区别
- 使用范围不一样
过滤器仅是Servlet的实现规范,仅在tomcat等容器中调用,即在web容器中使用
拦截器是Spring中实现,不仅在web容器中使用,可以在Application和Swing程序中。
- 拦截时机不一样
请求过来,先进入到tomcat容器,流转到Filter,具体到Servlet的Service方法,被DispatcherServlet流转到Interceptor链中,最后执行Controller的方法。
如下图:
- 拦截范围不一样
过滤器会拦截所有请求
拦截器仅会拦截Controller的请求和static资源目录下的请求
- 适用场景不一样
过滤器场景:字符转码、跨域问题
拦截器场景:权限控制,日志打印,参数校验
Filter过滤器调用源码分析
Filter调用时在Tomcat中实现,其中有容器StandardWrapperValve.invoke()方法中被创建执行。
public final void invoke(Request request, Response response) throws IOException, ServletException {
boolean unavailable = false;
// 省略...
request.setAttribute("org.apache.catalina.core.DISPATCHER_TYPE", dispatcherType);
request.setAttribute("org.apache.catalina.core.DISPATCHER_REQUEST_PATH", requestPathMB);
ApplicationFilterChain filterChain = ApplicationFilterFactory.createFilterChain(request, wrapper, servlet);
}
ApplicationFilterFactory.createFilterChain创建FilterChain
public static ApplicationFilterChain createFilterChain(ServletRequest request, Wrapper wrapper, Servlet servlet) {
if (servlet == null) {
return null;
} else {
// 1
ApplicationFilterChain filterChain = null;
if (request instanceof Request) {
Request req = (Request)request;
if (Globals.IS_SECURITY_ENABLED) {
filterChain = new ApplicationFilterChain();
} else {
filterChain = (ApplicationFilterChain)req.getFilterChain();
if (filterChain == null) {
filterChain = new ApplicationFilterChain();
req.setFilterChain(filterChain);
}
}
} else {
filterChain = new ApplicationFilterChain();
}
FilterMap[] filterMaps = context.findFilterMaps();
// 2
if (filterMaps != null && filterMaps.length != 0) {
int var11 = filterMaps.length;
int var12;
FilterMap filterMap;
ApplicationFilterConfig filterConfig;
// 2.1
for(var12 = 0; var12 < var11; ++var12) {
filterMap = var10[var12];
if (matchDispatcher(filterMap, dispatcher) && matchFiltersURL(filterMap, requestPath)) {
filterConfig = (ApplicationFilterConfig)context.findFilterConfig(filterMap.getFilterName());
if (filterConfig != null) {
filterChain.addFilter(filterConfig);
}
}
}
// 2.2
for(var12 = 0; var12 < var11; ++var12) {
filterMap = var10[var12];
if (matchDispatcher(filterMap, dispatcher) && matchFiltersServlet(filterMap, servletName)) {
filterConfig = (ApplicationFilterConfig)context.findFilterConfig(filterMap.getFilterName());
if (filterConfig != null) {
filterChain.addFilter(filterConfig);
}
}
}
return filterChain;
} else {
// 3
return filterChain;
}
}
}
-
创建ApplicationFilterChain类
-
判断Filter是否存在
2.2 过滤出匹配URL的Filter
2.3 过滤出匹配Servlet的Filter
3. Filter不存在,则直接返回filterChain
创建完ApplicationFilterChain后,调用doFilter方法
public void doFilter(ServletRequest request, ServletResponse response) throws IOException, ServletException {
if (Globals.IS_SECURITY_ENABLED) {
ServletRequest req = request;
ServletResponse res = response;
// 调用内部方法
try {
AccessController.doPrivileged(() -> {
this.internalDoFilter(req, res);
return null;
});
} catch (PrivilegedActionException var7) {
}
} else {
this.internalDoFilter(request, response);
}
}
private void internalDoFilter(ServletRequest request, ServletResponse response) throws IOException, ServletException {
// 1
if (this.pos < this.n) {
// 1.1
ApplicationFilterConfig filterConfig = this.filters[this.pos++];
try {
Filter filter = filterConfig.getFilter();
if (Globals.IS_SECURITY_ENABLED) {
} else {
// 1.2
filter.doFilter(request, response, this);
}
}
} else {
// 2
try {
if (request instanceof HttpServletRequest && response instanceof HttpServletResponse && Globals.IS_SECURITY_ENABLED) {
} else {
// 2.1
this.servlet.service(request, response);
}
}
}
}
- 当前Filter的pos小于Filters.length的长度
1.1 pos的位置+1
1.2 调用Filter的doFilter方法
2. filter调用完成或者无Filter时
2.1 调用servlet.service方法
分析完Filter的调用源码后,得到是Filter使用了责任链的模型,多个Filter则进行传递,直到最后一个,然后调用Servlet.service方法。
HandlerInterceptor拦截器调用源码分析
拦截器在Spring中DispatcherServlet的doDispatch中有具体实现
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
HttpServletRequest processedRequest = request;
HandlerExecutionChain mappedHandler = null;
boolean multipartRequestParsed = false;
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
try {
try {
ModelAndView mv = null;
Object dispatchException = null;
try {
// 1
mappedHandler = this.getHandler(processedRequest);
if (mappedHandler == null) {
this.noHandlerFound(processedRequest, response);
return;
}
HandlerAdapter ha = this.getHandlerAdapter(mappedHandler.getHandler());
String method = request.getMethod();
boolean isGet = HttpMethod.GET.matches(method);
// 2
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
// 3
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
if (asyncManager.isConcurrentHandlingStarted()) {
return;
}
// 4
mappedHandler.applyPostHandle(processedRequest, response, mv);
}
// 5
this.processDispatchResult(processedRequest, response, mappedHandler, mv, (Exception)dispatchException);
}
} finally {
}
}
-
获取HandlerExecutionChain对象,该对象封装了HandlerInteceptor的调用方法。
-
执行HandlerInterceptor的PreHandle方法
-
执行具体Controller下的服务
-
执行HandlerInterceptor的PostHandle方法
-
执行HandlerInterceptor的AfterCompletion方法
boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception {
// 遍历interceptor方法,如果某个interceptor返回false,则直接调用interceptor的
// AfterCompletion方法
for(int i = 0; i < this.interceptorList.size(); this.interceptorIndex = i++) {
HandlerInterceptor interceptor = (HandlerInterceptor)this.interceptorList.get(i);
if (!interceptor.preHandle(request, response, this.handler)) {
this.triggerAfterCompletion(request, response, (Exception)null);
return false;
}
}
return true;
}
void triggerAfterCompletion(HttpServletRequest request, HttpServletResponse response, @Nullable Exception ex) {
for(int i = this.interceptorIndex; i >= 0; --i) {
// 从最后一个HandlerInterceptor执行AfterCompletion方法
HandlerInterceptor interceptor = (HandlerInterceptor)this.interceptorList.get(i);
interceptor.afterCompletion(request, response, this.handler, ex);
}
}
// 从最后一个HandlerInterceptor执行postHandle方法
void applyPostHandle(HttpServletRequest request, HttpServletResponse response, @Nullable ModelAndView mv) throws Exception {
for(int i = this.interceptorList.size() - 1; i >= 0; --i) {
HandlerInterceptor interceptor = (HandlerInterceptor)this.interceptorList.get(i);
interceptor.postHandle(request, response, this.handler, mv);
}
}