1. 程式人生 > >關於Filter執行順序的探究

關於Filter執行順序的探究

今天研究一下Filter的執行順序問題。

首先,我寫了三個Filter


三個Filter的內容是一樣的,用不同列印來區分,這裡我只給出FirstFiler為例

package com.zhwy.filters;

import java.io.IOException;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.Filter;

public class FirstFilter implements Filter{

public void init(FilterConfig config) throws ServletException {
//獲取初始化引數
String first = config.getInitParameter("First");
System.out.println(first);
}

public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) 
throws IOException,ServletException {

System.out.println("This is FirstFilter...");
//把請求傳回過濾鏈
chain.doFilter(request, response);
System.out.println("FirstFilter over!");
}

public void destroy(){
System.out.println("FirstFilter was destroyed");
}
}

我們先以正常順序走一遍:

web.xml檔案配置如下:

<!--過濾器1 -->
	<filter>
		<filter-name>LogFilter</filter-name>
		<filter-class>com.zhwy.filters.FirstFilter</filter-class>
		<init-param>
			<param-name>First</param-name>
			<param-value>第一個Filter</param-value>
		</init-param>
	</filter>
	<filter-mapping>
		<filter-name>LogFilter</filter-name>
		<url-pattern>/*</url-pattern>
	</filter-mapping>

	<!--過濾器2 -->
	<filter>
		<filter-name>LogFilter2</filter-name>
		<filter-class>com.zhwy.filters.SecondFilter</filter-class>
		<init-param>
			<param-name>Second</param-name>
			<param-value>第二個Filter</param-value>
		</init-param>
	</filter>
	<filter-mapping>
		<filter-name>LogFilter2</filter-name>
		<url-pattern>/*</url-pattern>
	</filter-mapping>

	<!--過濾器3 -->
	<filter>
		<filter-name>LogFilter3</filter-name>
		<filter-class>com.zhwy.filters.ThirdFilter</filter-class>
		<init-param>
			<param-name>Third</param-name>
			<param-value>第三個Filter</param-value>
		</init-param>
	</filter>
	<filter-mapping>
		<filter-name>LogFilter3</filter-name>
		<url-pattern>/*</url-pattern>
	</filter-mapping>

首先Tomcat載入專案,Filter初始化,執行init() 方法,列印如下:

訪問index.jsp,列印如下:


可以看出,doFilter()最初執行時是按順序執行的,當執行完所有Filter鏈時,又從最近的這個Filter返回執行。

下面我將ThirdFilter的所有配置資訊在web.xml中移至最前面,即3-1-2的順序。

        <!--過濾器3 -->
	<filter>
		<filter-name>LogFilter3</filter-name>
		<filter-class>com.zhwy.filters.ThirdFilter</filter-class>
		<init-param>
			<param-name>Third</param-name>
			<param-value>第三個Filter</param-value>
		</init-param>
	</filter>
	<filter-mapping>
		<filter-name>LogFilter3</filter-name>
		<url-pattern>/*</url-pattern>
	</filter-mapping>
	<!--過濾器1 -->
      ...
      <!--過濾器2 -->
       ...

Tomcat載入如下:


訪問index.jsp:


可以看出,doFilter()依然按web.xml中的順序執行,執行完Filter鏈時,依然原路返回。

但是,最初的init()方法卻依然記憶了上一次的順序。

接著我僅將ThirdFilter的配置資訊提前,而仍然將其對映<filter-mapping>放在後面

  <!--過濾器3 -->
	<filter>
		<filter-name>LogFilter3</filter-name>
		<filter-class>com.zhwy.filters.ThirdFilter</filter-class>
		<init-param>
			<param-name>Third</param-name>
			<param-value>第三個Filter</param-value>
		</init-param>
	</filter>
	
   <!--過濾器1 -->
      ...
   <!--過濾器2 -->
       ...
     <filter-mapping>
		<filter-name>LogFilter3</filter-name>
		<url-pattern>/*</url-pattern>
     </filter-mapping>

初始化順序依然保留記憶


而訪問index時,filter的執行順序是按照對映資訊順序,即<filter-mapping>順序執行的


綜上,

在doFilter()方法中,

chain.doFilter()方法之前,

doFilter()的執行順序是按照web.xml中的配置順序執行的,確切的說,按照<filter-mapping>的順序執行的。

而呼叫完chain.doFilter()方法後,即當filter鏈中的filter都按順序執行完畢,像堆疊一樣,filter又從最近的一個開始執行。

另外,

在init()方法中,

似乎只按照容器第一次載入時初始化的順序執行,其後的順序不會影響。

最後,

關於destroy()方法,

只有在與容器斷開,即使用者與伺服器斷開,session結束時才會呼叫。