美文网首页java技术交流社区
关于Servlet Filter使用的责任链模式,这一篇简直讲的

关于Servlet Filter使用的责任链模式,这一篇简直讲的

作者: 程序员伟杰 | 来源:发表于2021-05-11 15:52 被阅读0次

    前言

    Servlet中的Filter使用到了责任链模式,Filter是提供给用户对请求做处理的,不同的组件可能有不同的处理,所以他们的处理逻辑不会耦合在一起,这样就需要一个方案将这些不同组件产生的分散且不确定的处理逻辑聚集起来,让他们得到执行,责任链模式就是一个优雅的解决方案,我们直接以Servlet中Filter的处理来做讲解,实战才是最好的讲解。

    个人整理了一些资料,有需要的朋友可以直接点击领取。

    Java基础知识大全

    百本本Java架构师核心书籍

    对标阿里P8的Java学习路线和资料

    2021年最新java面试题合集

    Filter

    我们先来看看顶级接口设计
    javax.servlet.Filter 直接暴露给用户实现的,需要处理的用户只要实现Filter,并将Filter添加到Servet容器中,就能够得到执行,Filter聚合了FilterConfig
    javax.servlet.FilterConfig 过滤器配置,包含对应一个真实的Filter
    javax.servlet.FilterChain 过滤器链,有一个FilterConfig列表,用来驱动执行下一个Filter逻辑,以及添加Filter到链上,这个类是主要逻辑所在地方,如果是你设计,你会把主要逻辑放在哪里?
    这里可以看到Filter和FilterConfig互为聚合对象,有点循环引用的意思。

    public interface Filter {
     
        public default void init(FilterConfig filterConfig) throws ServletException {}
     
        public void doFilter(ServletRequest request, ServletResponse response,
                FilterChain chain) throws IOException, ServletException;
     
        public default void destroy() {}
    }
     
    public abstract class GenericFilter implements Filter, FilterConfig, Serializable {
     
        private static final long serialVersionUID = 1L;
     
        private volatile FilterConfig filterConfig;
     
     
        @Override
        public String getInitParameter(String name) {
            return getFilterConfig().getInitParameter(name);
        }
     
        @Override
        public Enumeration<String> getInitParameterNames() {
            return getFilterConfig().getInitParameterNames();
        }
     
        public FilterConfig getFilterConfig() {
            return filterConfig;
        }
     
        @Override
        public ServletContext getServletContext() {
            return getFilterConfig().getServletContext();
        }
     
        @Override
        public void init(FilterConfig filterConfig) throws ServletException {
            this.filterConfig  = filterConfig;
            init();
        }
     
        public void init() throws ServletException {
            // NO-OP
        }
     
        @Override
        public String getFilterName() {
            return getFilterConfig().getFilterName();
        }
     
    }
    
    public interface FilterConfig {
        public String getFilterName();
     
        public ServletContext getServletContext();
     
        public String getInitParameter(String name);
     
        public Enumeration<String> getInitParameterNames();
    }
     
    public final class ApplicationFilterConfig implements FilterConfig, Serializable {
        ...
     
        private transient Filter filter = null;
     
        Filter getFilter() throws ClassCastException, ReflectiveOperationException, ServletException,
                NamingException, IllegalArgumentException, SecurityException {
     
            // Return the existing filter instance, if any
            if (this.filter != null)
                return this.filter;
     
            // Identify the class loader we will be using
            String filterClass = filterDef.getFilterClass();
            this.filter = (Filter) context.getInstanceManager().newInstance(filterClass);
     
            initFilter();
     
            return this.filter;
     
        }
    }
    

    这里看到包含的是一个FilterConfig数组,从FilterConfig中能够拿到Filter,说明FilterConfig是更加高层的对象, 高层对象聚合底层对象,高层对象被使用,在做设计时应该注意到。

    public interface FilterChain {
     
        public void doFilter(ServletRequest request, ServletResponse response)
                throws IOException, ServletException;
     
    }
     
    public final class ApplicationFilterChain implements FilterChain {
     
        private ApplicationFilterConfig[] filters = new ApplicationFilterConfig[0];
     
        @Override
        public void doFilter(ServletRequest request, ServletResponse response)
            throws IOException, ServletException {
     
            if( Globals.IS_SECURITY_ENABLED ) {
                final ServletRequest req = request;
                final ServletResponse res = response;
                try {
                    java.security.AccessController.doPrivileged(
                        new java.security.PrivilegedExceptionAction<Void>() {
                            @Override
                            public Void run()
                                throws ServletException, IOException {
                                internalDoFilter(req,res);
                                return null;
                            }
                        }
                    );
                } catch( PrivilegedActionException pe) {
                    Exception e = pe.getException();
                    if (e instanceof ServletException)
                        throw (ServletException) e;
                    else if (e instanceof IOException)
                        throw (IOException) e;
                    else if (e instanceof RuntimeException)
                        throw (RuntimeException) e;
                    else
                        throw new ServletException(e.getMessage(), e);
                }
            } else {
                internalDoFilter(request,response);
            }
        }
     
        private void internalDoFilter(ServletRequest request,
                                      ServletResponse response)
            throws IOException, ServletException {
     
            // Call the next filter if there is one
            if (pos < n) {
                ApplicationFilterConfig filterConfig = filters[pos++];
                try {
                    Filter filter = filterConfig.getFilter();
     
                    if (request.isAsyncSupported() && "false".equalsIgnoreCase(
                            filterConfig.getFilterDef().getAsyncSupported())) {
                        request.setAttribute(Globals.ASYNC_SUPPORTED_ATTR, Boolean.FALSE);
                    }
                    if( Globals.IS_SECURITY_ENABLED ) {
                        final ServletRequest req = request;
                        final ServletResponse res = response;
                        Principal principal =
                            ((HttpServletRequest) req).getUserPrincipal();
     
                        Object[] args = new Object[]{req, res, this};
                        SecurityUtil.doAsPrivilege ("doFilter", filter, classType, args, principal);
                    } else {
                        filter.doFilter(request, response, this);
                    }
                } catch (IOException | ServletException | RuntimeException e) {
                    throw e;
                } catch (Throwable e) {
                    e = ExceptionUtils.unwrapInvocationTargetException(e);
                    ExceptionUtils.handleThrowable(e);
                    throw new ServletException(sm.getString("filterChain.filter"), e);
                }
                return;
            }
     
            // We fell off the end of the chain -- call the servlet instance
            try {
                if (ApplicationDispatcher.WRAP_SAME_OBJECT) {
                    lastServicedRequest.set(request);
                    lastServicedResponse.set(response);
                }
     
                if (request.isAsyncSupported() && !servletSupportsAsync) {
                    request.setAttribute(Globals.ASYNC_SUPPORTED_ATTR,
                            Boolean.FALSE);
                }
                // Use potentially wrapped request from this point
                if ((request instanceof HttpServletRequest) &&
                        (response instanceof HttpServletResponse) &&
                        Globals.IS_SECURITY_ENABLED ) {
                    final ServletRequest req = request;
                    final ServletResponse res = response;
                    Principal principal =
                        ((HttpServletRequest) req).getUserPrincipal();
                    Object[] args = new Object[]{req, res};
                    SecurityUtil.doAsPrivilege("service",
                                               servlet,
                                               classTypeUsedInService,
                                               args,
                                               principal);
                } else {
                    servlet.service(request, response);
                }
            } catch (IOException | ServletException | RuntimeException e) {
                throw e;
            } catch (Throwable e) {
                e = ExceptionUtils.unwrapInvocationTargetException(e);
                ExceptionUtils.handleThrowable(e);
                throw new ServletException(sm.getString("filterChain.servlet"), e);
            } finally {
                if (ApplicationDispatcher.WRAP_SAME_OBJECT) {
                    lastServicedRequest.set(null);
                    lastServicedResponse.set(null);
                }
            }
        }
    }
    

    Interceptor

    Filter是个很简单的模式,Spring MVC中的Interceptor和Filter有所不同,因为Filter只能在请求前处理,不能在请求后处理,所以功能上有一些局限,所以Spring提供了Interceptor,所以有了Interceptor之后,如非特殊情况,我们一般使用Interceptor来满足需求。先来看看顶级接口:
    org.springframework.web.servlet.HandlerInterceptor

    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 {
        }
     
    }
    

    org.springframework.web.servlet.HandlerExecutionChain
    这里可以看到是直接遍历把所有前置,后置方法轮流调完。不是动态代理完成的。

    public class HandlerExecutionChain {
            ...
     
        @Nullable
        private HandlerInterceptor[] interceptors;
     
        boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception {
            HandlerInterceptor[] interceptors = getInterceptors();
            if (!ObjectUtils.isEmpty(interceptors)) {
                for (int i = 0; i < interceptors.length; i++) {
                    HandlerInterceptor interceptor = interceptors[i];
                    if (!interceptor.preHandle(request, response, this.handler)) {
                        triggerAfterCompletion(request, response, null);
                        return false;
                    }
                    this.interceptorIndex = i;
                }
            }
            return true;
        }
     
        /**
         * Apply postHandle methods of registered interceptors.
         */
        void applyPostHandle(HttpServletRequest request, HttpServletResponse response, @Nullable ModelAndView mv)
                throws Exception {
     
            HandlerInterceptor[] interceptors = getInterceptors();
            if (!ObjectUtils.isEmpty(interceptors)) {
                for (int i = interceptors.length - 1; i >= 0; i--) {
                    HandlerInterceptor interceptor = interceptors[i];
                    interceptor.postHandle(request, response, this.handler, mv);
                }
            }
        }
     
        /**
         * Trigger afterCompletion callbacks on the mapped HandlerInterceptors.
         * Will just invoke afterCompletion for all interceptors whose preHandle invocation
         * has successfully completed and returned true.
         */
        void triggerAfterCompletion(HttpServletRequest request, HttpServletResponse response, @Nullable Exception ex)
                throws Exception {
     
            HandlerInterceptor[] interceptors = getInterceptors();
            if (!ObjectUtils.isEmpty(interceptors)) {
                for (int i = this.interceptorIndex; i >= 0; i--) {
                    HandlerInterceptor interceptor = interceptors[i];
                    try {
                        interceptor.afterCompletion(request, response, this.handler, ex);
                    }
                    catch (Throwable ex2) {
                        logger.error("HandlerInterceptor.afterCompletion threw exception", ex2);
                    }
                }
            }
        }
    }
    

    最后

    就先总结到这里了,觉得有帮助的可以帮忙点个赞,感谢支持!

    相关文章

      网友评论

        本文标题:关于Servlet Filter使用的责任链模式,这一篇简直讲的

        本文链接:https://www.haomeiwen.com/subject/usxndltx.html