JavaWeb--Filter

一、基本概念

之前我們用一篇博文介紹了Servlet相關(guān)的知識(shí),有了那篇博文的知識(shí)積淀,今天我們學(xué)習(xí)Filter將會(huì)非常輕松,因?yàn)镕ilter有很多地方和Servlet類似,下面在講Filter的時(shí)候,就閑話不絮了。

Filter稱之為過(guò)濾器,是用來(lái)做一些攔截的任務(wù)。比如客戶端請(qǐng)求服務(wù)器的某個(gè)資源時(shí)(可以是Servlet、JSP、HTML等等),我們可以攔截。當(dāng)服務(wù)器返回資源給客戶端的時(shí)候,我們也可以攔截。這樣我們就可以在調(diào)用資源之前和之后分別加入一些業(yè)務(wù)邏輯。

Filter的位置

當(dāng)我們對(duì)某個(gè)資源加上多個(gè)過(guò)濾器的時(shí)候,就形成了過(guò)濾鏈。請(qǐng)求(request)會(huì)依次通過(guò)鏈上的過(guò)濾器,響應(yīng)(response)會(huì)依次以相反的順序通過(guò)過(guò)濾器。

過(guò)濾鏈

二、樣例分析

和使用servlet一樣,要使用filter只需要兩步:1.編寫自己的filter,實(shí)現(xiàn)javax.servlet.Filter。2.在web.xml中注冊(cè)該filter。

TestFilter.java

public class TestFilter implements Filter {
    public TestFilter() {}
    
    public void init(FilterConfig fConfig) throws ServletException {}

    public void destroy() {}

    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        System.out.println("before doFilter");
        chain.doFilter(request, response);
        System.out.println("after doFilter");
    }
}

web.xml

<filter>
    <filter-name>TestFilter</filter-name>
    <filter-class>com.nantang.filter.TestFilter</filter-class>
</filter>
<filter-mapping>
    <filter-name>TestFilter</filter-name>
    <url-pattern>/test</url-pattern>
</filter-mapping>

假定我們?cè)诒緳C(jī)部署應(yīng)用,應(yīng)用上下文路徑是/demo,那么在瀏覽器里面輸入http://localhost:8080/demo/test。則在控制臺(tái)會(huì)輸出:"before doFilter"和"after doFilter"。這是我們的請(qǐng)求和響應(yīng)受到了攔截,在調(diào)用具體的Servlet或其他資源前后執(zhí)行了我們編寫的邏輯(例子中就是往控制臺(tái)打印信息)。

這里需要注意的是,filter可以對(duì)url進(jìn)行過(guò)濾,也可以針對(duì)具體的servlet進(jìn)行過(guò)濾,只需要制定servlet的名稱,如:

<filter-mapping>
    <filter-name>TestFilter</filter-name>
    <servlet-name>TestServlet</servlet-name>
</filter-mapping>

三、源碼分析

我們自己編寫的filter都需要實(shí)現(xiàn)javax.servlet.Filter接口,下面我們看一下Filter接口的繼承層級(jí),并逐一分析。

Filter源碼

1 FilterConfig

當(dāng)容器去初始化一個(gè)filter的時(shí)候,就會(huì)根據(jù)web.xml文件的配置和當(dāng)前的運(yùn)行環(huán)境去構(gòu)造一個(gè)FilterCongif實(shí)例并傳給filter。所以一個(gè)filter對(duì)應(yīng)一個(gè)FilterConfig實(shí)例。

Filter層級(jí)
public interface FilterConfig {

    public String getFilterName();

    public ServletContext getServletContext();

    public String getInitParameter(String name);

    public Enumeration getInitParameterNames();
}

getFilterName方法返回我們?cè)趙eb.xml里面配置的名稱。

getServletContext返回ServletContext實(shí)例,這個(gè)和之前介紹Servlet的時(shí)候講到的是一個(gè)東西。一個(gè)應(yīng)用就一個(gè)ServletContext實(shí)例。

getInitParameter和getInitParameterNames和Servlet的類似。就是獲取在web.xml里面配置的初始化參數(shù),如:

<filter>
    <filter-name>TestFilter</filter-name>
    <filter-class>com.nantang.filter.TestFilter</filter-class>
    <init-param>
        <param-name>param1</param-name>
        <param-value>1</param-value>
    </init-param>
    <init-param>
        <param-name>param2</param-name>
        <param-value>2</param-value>
    </init-param>
</filter>

2 FilterChain

FilterChain就是我們上面說(shuō)的過(guò)濾鏈,當(dāng)請(qǐng)求或響應(yīng)被filter攔截時(shí),容器提供FilterChain實(shí)例給filter讓其使用。

public interface FilterChain {
    
    public void doFilter ( ServletRequest request, ServletResponse response ) throws IOException, ServletException;
}

FilterChain里面就一個(gè)方法doFilter,這個(gè)方法就是調(diào)用過(guò)濾鏈的下一個(gè)filter,如果當(dāng)前filter是鏈中最后的一個(gè),則跳轉(zhuǎn)至請(qǐng)求的資源或返回響應(yīng)給客戶端。

3 Filter

Filter里面就三個(gè)方法,也就是它的生命周期。和Servlet類似。

public interface Filter {

    public void init(FilterConfig filterConfig) throws ServletException;
    
    public void doFilter ( ServletRequest request, ServletResponse response, FilterChain chain ) throws IOException, ServletException;

    public void destroy();
}
Filter生命周期

3.1 init

filter的初始化方法,跟servlet一樣在其生命周期內(nèi)只會(huì)被執(zhí)行一次。但是filter初始化的時(shí)機(jī)和servlet不一樣,當(dāng)servlet容器(比如Tomcat)啟動(dòng)完成后就會(huì)檢索web.xml里面配置的filter,從上往下依次回調(diào)每個(gè)filter的init方法對(duì)其進(jìn)行初始化。(這里的filterConfig參數(shù)是容器構(gòu)造并傳入的。)

3.2 doFilter

實(shí)現(xiàn)攔截邏輯的地方,比如一個(gè)請(qǐng)求被攔截,這里可以在調(diào)用具體資源之前編寫一些業(yè)務(wù)邏輯。然后調(diào)用chain.doFilter流轉(zhuǎn)到后置filter,如果當(dāng)前filter是鏈中最后的一個(gè),則跳轉(zhuǎn)至請(qǐng)求的資源。當(dāng)chain.doFilter執(zhí)行完成后,可以再寫一些業(yè)務(wù)邏輯。然后容器將執(zhí)行權(quán)流轉(zhuǎn)到前置filter,如果當(dāng)前filter是鏈中最前的一個(gè),則將響應(yīng)返回給客戶端。(這里的參數(shù)chain是容器構(gòu)造并傳入的。)

3.3 destory

和servlet的destroy方法同樣的道理,當(dāng)servlet容器關(guān)閉或需要更多內(nèi)存的時(shí)候,會(huì)銷毀filter。這個(gè)方法就使得servlet容器擁有回收資源的能力。
同樣地,destroy方法在filter的生命周期中只會(huì)被調(diào)用一次。

四、總結(jié)

到這里filter就算結(jié)束了,我們可以發(fā)現(xiàn)filter的執(zhí)行模型和servlet很類似,都是servlet容器在調(diào)度。整個(gè)生命周期都是容器在管控。

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

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容