乾貨,一文帶你超詳細瞭解 Filter 的原理及應用

Filter 簡介html

什麼是 filter程序員

1) Filter(過濾器) 的基本功能是對 Servlet 容器調用 Servlet (JSP)的過程進行攔截, 從而在 Servlet 處理請求前和Servlet 響應請求後實現一些特殊的功能。web

2) 在 Servlet API 中定義了三個接口類來開供開發人員編寫 Filter 程序: Filter,FilterChain, FilterConfig服務器

3) Filter 程序是一個實現了 Filter 接口的 Java 類,與 Servlet 程序類似,它由 Servlet容器進行調用和執行app

4) Filter 程序須要在 web.xml 文件中進行註冊和設置它所能攔截的資源:Filter 程序能夠攔截 Jsp, Servlet, 靜態圖片文件和靜態 html 文件jsp

filter 的運行原理是什麼分佈式

 

這個 Servlet 過濾器就是咱們的 filteride

1)當在 web.xml 中註冊了一個 Filter 來對某個 Servlet 程序進行攔截處理時,這個Filter 就成了 Tomcat 與該 Servlet 程序的通訊線路上的一道關卡,該 Filter 能夠對Servlet 容器發送給 Servlet 程序的請求和 Servlet 程序回送給 Servlet 容器的響應進行攔截,能夠決定是否將請求繼續傳遞給 Servlet 程序,以及對請求和相應信息是否進行修改微服務

2)在一個 web 應用程序中能夠註冊多個 Filter 程序,每一個 Filter 程序均可以對一個或一組 Servlet 程序進行攔截。源碼分析

3)如有多個 Filter 程序對某個 Servlet 程序的訪問過程進行攔截,當針對該 Servlet 的訪問請求到達時,web 容器將把這多個 Filter 程序組合成一個 Filter 鏈(過濾器鏈)。Filter 鏈中各個 Filter 的攔截順序與它們在應用程序的 web.xml 中映射的順序一致

Filter-helloword

Hello-World

filter 編寫三步驟:

一、建立 filter 實現類,實現 filter 接口

二、編寫 web.xml 配置文件,配置 filter 的信息

三、運行項目,能夠看到 filter 起做用了

代碼:

 
//一、filter 實現類 public class MyFirstFilter implements Filter{ @Override public void init(FilterConfig filterConfig) throws ServletException { System.out.println("初始化方法"); } @Override public void doFilter(ServletRequest request, ServletResponse response,FilterChain chain) throws IOException, ServletException { System.out.println("dofilter方法"); } @Override public void destroy() { System.out.println("銷燬方法..."); } } //二、web.xml 配置 <filter> <filter-name>MyFirstFilter</filter-name> <filter-class>com.atguigu.filter.MyFirstFilter</filter-class> </filter> <filter-mapping> <filter-name>MyFirstFilter</filter-name> <url-pattern>/index.jsp</url-pattern> </filter-mapping> //三、運行程序,發現 index.jsp 頁面不顯示了,後臺輸出「dofilter 方法」,說明咱們寫的 filter 執行了。

filter 的生命週期

1)在服務器啓動時,filter 被建立並初始化,執行 init()方法。

2)請求經過 filter 時執行 doFilter 方法。

3)服務器中止時,調用 destroy 方法。

filter 放行請求

咱們發現,剛纔的 filter 配置好後,index.jsp 頁面無法訪問了,訪問這個頁面的時候 filter的 dofilter 方法被調用了。說明dofilter 這個方法攔截了咱們的請求。

咱們如何顯示頁面呢。也就是如何將請求放行呢。咱們觀察發現有個 filterChain 被傳入到這個方法裏面了。filterChain 裏面有個 doFilter()方法。放行請求只須要調用 filterChain 的 dofilter 方法。

 
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException,ServletException { System.out.println("dofilter方法"); chain.doFilter(request, response);//放行請求 }

filter 攔截原理

咱們在 chain.doFilter(request, response);方法後也寫一句話,System.out.println

(「doFilter 方法執行後…」),在 index.jsp 頁面也寫上 jsp 腳本片斷,輸出我是 jsp 頁面。運行程序發現控制檯輸出了這幾句話:

 
dofilter 方法… 我是 jsp 頁面 dofilter 方法後… 咱們不難發現 filter 的運行流程

 

 

FilterChain

doFilter(ServletRequest request, ServletResponse response, FilterChain chain)

在 doFilter 執行以前,由容器將 filterChain 對象傳入方法。調用此對象的.doFilter()方法能夠將請求放行,其實是執行過濾器鏈中的下一個 doFilter 方法,可是若是隻有一個過濾器,則爲放行。

 

FilterConfig

FilterConfig 相似 ServletConfig,是 filter 的配置信息對象。FilterConfig 對象具備如下方法。

 

getFilterName():獲取當前 filter 的名字。獲取的是在 web.xml 中配置的 filter-name 的值

getInitParameter(String name):獲取 filter 的初始化參數。在 web.xml 中配置

 

getInitParameterNames():獲取 filter 初始化參數名的集合。

getServletContext():獲取當前 web 工程的 ServletContext 對象。

 

Filter 的 url-pattern

url-pattern 是配置 filter 過濾哪些請求的。主要有如下幾種配置:

web.xml 中配置的/都是以當前項目路徑爲根路徑的

1)精確匹配:

/index.jsp/user/login 會在請求/index.jsp、/user/login 的時候執行過濾方法

2)路徑匹配:

/user/* /* 凡是路徑爲/user/下的全部請求都會被攔截,/*表示攔截系統的全部請求,包括靜態資源文件。

3)擴展匹配:

*.jsp *.action 凡是後綴名爲.jsp .action 的請求都會被攔截。

注意:/login/*.jsp 這種寫法是錯誤的,只能是上述三種的任意一種形式。不能組合新形式。

*jsp 也是錯誤的,擴展匹配必須是後綴名

4)多重 url-pattern 配置

上面的三種形式比較有侷限性,可是 url-pattern 能夠配置多個,這樣這三種組合基本就能解決全部問題了

 

多 Filter 執行順序

若是同一個資源有多個 filter 都對其攔截,則攔截的順序是按照 web.xml 中配置的順序進行的

執行流程圖以下

 

請求老是在處理以後再回來執行 doFilter 以後的方法。

 

HttpServletWrapper 和 HttpServletResponseWrapper

定義

Servlet API 中提供了一個 HttpServletRequestWrapper 類來包裝原始的 request 對象,HttpServletRequestWrapper 類實現了 HttpServletRequest 接口中的全部方法, 這些方法的內部實現都是僅僅調用了一下所包裝的的 request 對象的對應方法

 
//包裝類實現 ServletRequest 接口.  public class ServletRequestWrapper implements ServletRequest { //被包裝的那個 ServletRequest 對象 private ServletRequest request; //構造器傳入 ServletRequest 實現類對象 public ServletRequestWrapper(ServletRequest request) { if (request == null) { throw new IllegalArgumentException("Request cannot be null"); } this.request = request; } //具體實現 ServletRequest 的方法: 調用被包裝的那個成員變量的方法實現。  public Object getAttribute(String name) { return this.request.getAttribute(name); } public Enumeration getAttributeNames() { return this.request.getAttributeNames(); } //...  }

相相似 Servlet API 也提供了一個 HttpServletResponseWrapper 類來包裝原始的 response 對象

做用

用於對 HttpServletRequest 或 HttpServletResponse 的某一個方法進行修改或加強.

 
public class MyHttpServletRequest extends HttpServletRequestWrapper{ public MyHttpServletRequest(HttpServletRequest request) { super(request); } @Override public String getParameter(String name) { String val = super.getParameter(name); if(val != null && val.contains(" fuck ")){ val = val.replace("fuck", "****"); } return val; } }

程序員寫代碼以外,如何再賺一份工資?

使用

在 Filter 中, 利用 MyHttpServletRequest 替換傳入的 HttpServletRequest

 
HttpServletRequest req = new MyHttpServletRequest(request); filterChain.doFilter(req, response);

此時到達目標 Servlet 或 JSP 的 HttpServletRequest 其實是 MyHttpServletRequest

若是想學習Java工程化、高性能及分佈式、深刻淺出。微服務、Spring,MyBatis,Netty源碼分析的朋友能夠加個人Java高級交流:787707172,羣裏有阿里大牛直播講解技術,以及Java大型互聯網技術的視頻免費分享給你們。

相關文章
相關標籤/搜索