JavaWeb 三大器--Listener、Filter 和Interceptor 總結
說明:web.xml的載入順序是:【Context-Param】->【Listener】->【Filter】->【Servlet】,而同個型別之間的實際程式呼叫的時候的順序是根據對應的Mapping的順序進行呼叫。
詳細介紹:web.xml載入順序與web.xml常用節點解析
轉自:https://www.cnblogs.com/hellovoyager1/p/9152292.html
一、背景
這段時間因為工作不忙,所以有時間來總結整理一下之前遇到的一些問題。在之前專案開發過程中碰到過關於攔截器、過濾器之類的問題(發現自己基礎真的薄弱,不過沒關係知識一點一滴積累),索性就記錄下來。由於筆者知識水平有限,如有不對的地方歡迎批評指正。
二、概念
在講解三大器之前,我們需要對Servlet 有所瞭解,因為這個通常是我們在接觸Javaweb 時最先了解到的知識點。
1. Servlet
Servlet 是sun 公司提供的一門用於開發動態web 資源的技術,主要功能在於互動式地瀏覽和修改資料,生成動態Web 頁面,我們實際開發應用中,一般不需要去研究Http 協議,只要擴充套件servlet 介面,即可實現web 伺服器應用程式的開發。通俗來講,就是這個技術可以實現一個由客戶端發起請求-->伺服器端處理-->客戶端得到響應的功能。額。。。還不是很有概念,那Servlet 得生命週期總有印象吧?
這裡說個題外話,提到Servlet 的生命週期,首先,這個在面試時經常被問到。
Servlet 生命週期可被定義為從建立直到毀滅的整個過程。以下是 Servlet 遵循的過程(三個重要方法):
①init () 方法進行初始化:
在Servlet的生命週期中,僅執行一次init()方法,它是在伺服器裝入Servlet時執行的,可以配置伺服器,以在啟動伺服器或客戶機首次訪問Servlet 時裝入Servlet。無論有多少客戶機訪問Servlet,都不會重複執行init();
②Servlet 呼叫 service() 方法來處理客戶端的請求:
它是Servlet的核心,每當一個客戶請求一個HttpServlet 物件,該物件的Service() 方法就要呼叫,而且傳遞給這個方法一個“請求”(ServletRequest)物件和一個“響應”(ServletResponse)物件作為引數。在HttpServlet 中已存在Service()方法。預設的服務功能是呼叫與HTTP請求的方法相應的do功能。
③Servlet 通過呼叫 destroy() 方法終止(結束):
僅執行一次,在伺服器端停止且解除安裝Servlet 時執行該方法,有點類似於C++ delete 方法。一個Servlet 在執行service() 方法時可能會產生其他的執行緒,因此需要確認在呼叫destroy() 方法時,這些執行緒已經終止或完成。
Servlet 的生命週期的話還需要加上在init() 之前有一個載入和例項化Servlet(反射機制)的過程。
整個過程大概是這樣的:
其次,還記得在大三那會去實習,組長給我們講解Java 知識的時候就有提到過Servlet。記得當時是做一個登入跳轉的功能,寫一個Java 類,實現Servlet 介面,然後寫doGet() 和doPost() 方法,因為這裡要處理亂碼來著,搞了半天。。。至此,這兩點大概是我對Servlet 的最深印象了吧。那麼,之後的工作中為什麼彷彿徹底與這東西無緣了一樣。時至今日,再次提起這個東西才知道一直有在用,只是自己不知道而已。
回到正題,現在我們的Servlet 哪裡去了呢?沒錯,它沒有消失,而是在我們的web.xml 檔案:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
<!-- spring mvc servlet -->
<servlet>
<description>spring mvc servlet</description>
<servlet-name>springMvc</servlet-name>
<servlet-
class
>org.springframework.web.servlet.DispatcherServlet</servlet-
class
>
<init-param>
<description>spring mvc 配置檔案</description>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring-mvc.xml</param-value>
</init-param>
<load-on-startup>
1
</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>springMvc</servlet-name>
<url-pattern>*.
do
</url-pattern>
</servlet-mapping>
|
通過這種方式我們就實現對*.do 這樣的請求進行統一處理,通常我們也把實現了servlet 介面的java 程式,稱之為Servlet。如果換成以前的寫法,就是這樣的:
Servlet 類:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
/**
* 使用者登入校驗
* Servlet implementation class LoginServlet
*/
@WebServlet
(
"/LoginServlet"
)
public
class
LoginServlet
extends
HttpServlet {
private
static
final
long
serialVersionUID = 1L;
public
LoginServlet() {
super
();
}
protected
void
doGet(HttpServletRequest request, HttpServletResponse response)
throws
ServletException, IOException {
this
.doPost(request, response);
}
protected
void
doPost(HttpServletRequest request, HttpServletResponse response)
throws
ServletException, IOException {
//String username = request.getParameter("username");
//String password = request.getParameter("password");
//...
// success
doGet(request, response);
}
}
|
web.xml 配置:
1 2 3 4 5 6 7 8 9 10 11 12 |
<servlet>
<!-- Servlet的註冊名稱 -->
<servlet-name>LoginServlet</servlet-name>
<!-- Servlet的完整類名 -->
<servlet-
class
>com.github.servlet.LoginServlet</servlet-
class
>
</servlet>
<servlet-mapping>
<!-- Servlet的註冊名稱 -->
<servlet-name>LoginServlet</servlet-name>
<!-- Servlet的對外訪問路徑 -->
<url-pattern>/servlet/loginServlet</url-pattern>
</servlet-mapping>
|
訪問路徑
看到這裡終於明白,現在每天都在用的DispatcherServlet 正是以前所接觸過得Servlet。進一步跟蹤DispatcherServlet 發現果然,他確實是實現了HttpServlet 介面
2.Listener
監聽器,從字面上可以看出listener 主要用來監聽時用。通過listener 可以監聽web 伺服器中某一個執行動作,並根據其要求作出相應的響應。通俗的語言說就是在application,session,request三個物件建立消亡或者往其中新增修改刪除屬性時自動執行程式碼的功能元件。
3.Filter
過濾器,是一個可以複用的程式碼片段,可以用來轉換HTTP請求、響應和頭資訊。Filter不像Servlet,它不能產生一個請求或者響應,它只是修改對某一資源的請求,或者修改從某一的響應。
4.Interceptor
攔截器,是在面向切面程式設計的,就是在你的service 或者一個方法,前呼叫一個方法,或者在方法後呼叫一個方法。比如動態代理就是攔截器的簡單實現,在你呼叫方法前打印出字串(或者做其它業務邏輯的操作),也可以在你呼叫方法後打印出字串,甚至在你丟擲異常的時候做業務邏輯的操作。
5.配置方式
servlet、filter、listener是配置到web.xml中,interceptor不配置到web.xml中,struts的攔截器配置到struts.xml中,spring的攔截器配置到spring.xml中。
三、生命週期
1、servlet:servlet的生命週期始於它被裝入web伺服器的記憶體時,並在web伺服器終止或重新裝入servlet時結束。servlet一旦被裝入web伺服器,一般不會從web伺服器記憶體中刪除,直至web伺服器關閉或重新結束。
(1)、裝入:啟動伺服器時載入Servlet的例項;
(2)、初始化:web伺服器啟動時或web伺服器接收到請求時,或者兩者之間的某個時刻啟動。初始化工作有init()方法負責執行完成;
(3)、呼叫:從第一次到以後的多次訪問,都是隻呼叫doGet()或doPost()方法;
(4)、銷燬:停止伺服器時呼叫destroy()方法,銷燬例項。
2、filter:(一定要實現javax.servlet包的Filter介面的三個方法init()、doFilter()、destroy(),空實現也行)
(1)、啟動伺服器時載入過濾器的例項,並呼叫init()方法來初始化例項;
(2)、每一次請求時都只調用方法doFilter()進行處理;
(3)、停止伺服器時呼叫destroy()方法,銷燬例項。
3、listener:類似於servlet和filter
web.xml 的載入順序是:context- param -> listener -> filter -> servlet
4、interceptor:以struts的攔截器為例,載入了struts.xml以後,初始化相應攔截器。當action請求來時呼叫intercept方法,伺服器停止銷燬interceptor。
四、總結
三大器對比:
ps:
1.平時所用的框架(Spring、Structs2等)其實都是基於JavaWeb 這四個知識點來做文章的,如果對原始的JavaWeb 不是很瞭解,那麼在理解這些框架(框架是大牛們對原始JavaWeb進行封裝的結果,沒有原始JavaWeb開發基礎是很難真正學會框架的)上只能是知道是這樣做,而不知道為什麼要這樣做,這種對框架的理解也只是存在表面上,稍微深入一點就得懵逼。
2.自己在實際工作中很多東西做完了就沒了,還是缺少一種獨立思考的能力。求學,不應該只是不求甚解,更應該有一種知之者不如好之者,好之者不如樂之者的心態,主動學習。
3.站在巨人的肩膀,能看的更遠。