Spring Interceptor vs Filter

Filter

Filter,顧名思義,過濾器,是由servlet容器爲每一個傳入的http請求和每一個http響應執行的Java類。 這樣,就能夠在HTTP傳入請求到達資源以前對其進行管理,例如JSP頁面,servlet或簡單的靜態頁面; 以相同的方式能夠在資源執行後管理HTTP出站響應。java

此行爲容許實如今許多不一樣上下文中重用的經常使用功能。web

Filter在只在 Servlet 先後起做用。Filters 一般將請求和響應(request/response) 當作黑盒子,Filter 一般不考慮servlet的實現。spring

如上圖所示,過濾器在Web容器中運行,所以其定義也將包含在web.xml文件中。apache

<filter>
    <filter-name>CORSFilter</filter-name>
    <filter-class>com.listfeeds.components.CORSFilter</filter-class>
    <init-param>
        <param-name>fake-param</param-name>
        <param-value>fake-param-value</param-value>
    </init-param>
</filter>
<filter-mapping>
    <filter-name>CORSFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>
複製代碼

在過濾器定義中,由com.listfeeds.filters.CORSFilter類實現的過濾器具備知足表達式的全部端點:/ *(在本例中爲all)安全

import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletResponse;
import org.springframework.stereotype.Component;

public class CORSFilter implements Filter {

    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {

        HttpServletResponse response = (HttpServletResponse) res;
        response.setHeader("Access-Control-Allow-Origin", "*");
        response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE");
        response.setHeader("Access-Control-Max-Age", "3600");
        response.setHeader("Access-Control-Allow-Headers", "x-requested-with");
        chain.doFilter(req, res);
    }

    public void init(FilterConfig filterConfig) {}

    public void destroy() {}

}
複製代碼

Filter包括三個主要方法:bash

  • init:執行以使用過濾器定義中的init-param元素初始化過濾器
  • doFilter:爲知足「url-pattern」的全部HTTP傳入請求執行
  • destroy:釋放過濾器使用的資源

Filter使用場景:mvc

  • 身份驗證:根據用戶身份阻止請求。
  • 記錄日誌和審覈:跟蹤Web應用程序的用戶。
  • 圖像轉換:縮放地圖等。
  • 數據壓縮:使下載量更小。
  • 本地化:將請求和響應定位到特定區域設置。

Request Filters 能夠:app

  • 執行安全檢查
  • 從新格式化請求標頭或正文
  • 請求記錄與審計

Response Filters 能夠:ide

  • 壓縮響應流
  • 追加或改變響應流
  • 徹底創造一個不一樣的迴應

Filter的輪子有:post

  • 認證 Filters
  • 日誌和請求審計 Filters
  • 圖像轉換 Filters
  • 數據壓縮 Filters
  • 加密 FIlter
  • ...

Interceptor

Spring攔截器相似於Servlet過濾器,但它們在Spring Context中起做用,所以管理HTTP請求和響應的功能很是強大,但它們能夠實現更加軟化的行爲,由於它能夠訪問全部Spring上下文。

Interceptor可以深刻到方法先後、異常拋出先後等,所以攔截器的使用具備更大的彈性。容許用戶介入(hook into)請求的生命週期,在請求過程當中獲取信息,Interceptor 一般和請求更加耦合。

Spring攔截器在SpringMVC上下文中執行,所以它們已在spring-servlet.xml文件中定義:

<mvc:interceptors>
    <bean class="com.listfeeds.interceptors.LogContextInterceptor" />
    <bean class="com.listfeeds.interceptors.TimedInterceptor" />
</mvc:interceptors>
複製代碼

com.listfeeds.interceptors.LogContextInterceptor攔截器類,用於向Log4j Thread上下文添加參數。

import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.lang.StringUtils;
import org.apache.log4j.MDC;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerMapping;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

public class LogContextInterceptor extends HandlerInterceptorAdapter {

    private static final Logger log = LoggerFactory.getLogger(LogContextInterceptor.class);

    public static final String LOG_IDENTIFYING_TOKEN = "logIdentifyingToken";

    @Override
    public void afterCompletion(
            HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
            throws Exception {

        HandlerMethod methodHandler = (HandlerMethod) handler;
        log.debug("END EXECUTION method {} request: {}", methodHandler.getMethod().getName(), request.getRequestURI());

        Boolean settato = (Boolean) request.getAttribute(LOG_IDENTIFYING_TOKEN);
        if(settato != null && settato) {
            MDC.remove(LOG_IDENTIFYING_TOKEN);
        }
    }

    @Override
    public boolean preHandle(HttpServletRequest request,
            HttpServletResponse response, Object handler) throws Exception {

        try {
            if( MDC.get(LOG_IDENTIFYING_TOKEN) == null ) {

                /* Retrieve parameters useful for logging */
                @SuppressWarnings("unchecked")
                Map<String,String> pathVariables = 
                (Map<String, String>) request.getAttribute(HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE);

                String applicationId = null;
                if ( pathVariables != null ) 
                    applicationId = pathVariables.get("applicationId");

                if ( StringUtils.isEmpty(applicationId) ) 
                    applicationId = request.getParameter("applicationId");

                String loggingToken = 
                        String.format("ApplicationId: %s", applicationId);

                MDC.put(LOG_IDENTIFYING_TOKEN, loggingToken);
                request.setAttribute(LOG_IDENTIFYING_TOKEN, Boolean.TRUE);
            }


        }
        catch ( IllegalArgumentException e)
        {
            log.warn("Prehandle",e);
            return true;
        }
        finally {
            HandlerMethod methodHandler = (HandlerMethod) handler;
            //logger.debug("START EXECUTION " + methodHandler.getMethod().getName());
            log.debug("START EXECUTION method {} request: {}", methodHandler.getMethod().getName(), request.getRequestURI());


        }


        return true;
    }

}
複製代碼

interceptor 包含以下幾個主要方法:

  • preHandle:在執行目標資源以前執行
  • afterCompletion:執行目標資源後執行(渲染視圖後)
  • posttHandle:攔截處理程序的執行
相關文章
相關標籤/搜索