關于Servlet Filter使用的責任鏈模式,這一篇簡直講的清新脫俗!

前言

Servlet中的Filter使用到了責任鏈模式,F(xiàn)ilter是提供給用戶對請求做處理的,不同的組件可能有不同的處理,所以他們的處理邏輯不會耦合在一起,這樣就需要一個方案將這些不同組件產(chǎn)生的分散且不確定的處理邏輯聚集起來,讓他們得到執(zhí)行,責任鏈模式就是一個優(yōu)雅的解決方案,我們直接以Servlet中Filter的處理來做講解,實戰(zhàn)才是最好的講解。

個人整理了一些資料,有需要的朋友可以直接點擊領取。

Java基礎知識大全

百本本Java架構師核心書籍

對標阿里P8的Java學習路線和資料

2021年最新java面試題合集

Filter

我們先來看看頂級接口設計
javax.servlet.Filter 直接暴露給用戶實現(xiàn)的,需要處理的用戶只要實現(xiàn)Filter,并將Filter添加到Servet容器中,就能夠得到執(zhí)行,F(xiàn)ilter聚合了FilterConfig
javax.servlet.FilterConfig 過濾器配置,包含對應一個真實的Filter
javax.servlet.FilterChain 過濾器鏈,有一個FilterConfig列表,用來驅動執(zhí)行下一個Filter邏輯,以及添加Filter到鏈上,這個類是主要邏輯所在地方,如果是你設計,你會把主要邏輯放在哪里?
這里可以看到Filter和FilterConfig互為聚合對象,有點循環(huán)引用的意思。

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數(shù)組,從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
這里可以看到是直接遍歷把所有前置,后置方法輪流調完。不是動態(tài)代理完成的。

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

最后

就先總結到這里了,覺得有幫助的可以幫忙點個贊,感謝支持!

?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

友情鏈接更多精彩內容