java 过滤器、拦截器

什么是过滤器

过滤器Filter是基于Servlet实现,对进入到Servlet的请求拦截。主要用于对字符编码,跨域等问题过滤。如下图:
7eac30666a16453ab87e7357829fca49.png
所有的请求和都经过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之前,会被拦截。
image.png

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");
    }
}

拦截器执行流程如下图:
拦截器执行图.png

过滤器和拦截器的区别

  1. 使用范围不一样

过滤器仅是Servlet的实现规范,仅在tomcat等容器中调用,即在web容器中使用
拦截器是Spring中实现,不仅在web容器中使用,可以在Application和Swing程序中。

  1. 拦截时机不一样

image.png
请求过来,先进入到tomcat容器,流转到Filter,具体到Servlet的Service方法,被DispatcherServlet流转到Interceptor链中,最后执行Controller的方法。
如下图:
image.png

  1. 拦截范围不一样

过滤器会拦截所有请求
拦截器仅会拦截Controller的请求和static资源目录下的请求

  1. 适用场景不一样

过滤器场景:字符转码、跨域问题
拦截器场景:权限控制,日志打印,参数校验

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;
            }
        }
    }
  1. 创建ApplicationFilterChain类

  2. 判断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);
                }
            }
        }
    }
  1. 当前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 {
        }
    }
  1. 获取HandlerExecutionChain对象,该对象封装了HandlerInteceptor的调用方法。

  2. 执行HandlerInterceptor的PreHandle方法

  3. 执行具体Controller下的服务

  4. 执行HandlerInterceptor的PostHandle方法

  5. 执行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);
    }

}
posted @ 2023-07-23 15:30  冰魄秋雨  阅读(906)  评论(0编辑  收藏  举报