最近在做將公司項目從Weblogic移植到GlassFish的工作,遇到的其中一個比較頭疼的問題就是Weblogic的LifeCycleManager。Weblogic提供了一個ApplicationLifecycleListener類可以在application部署和卸載時做一些工作,這是Weblogic獨有的特性,并不是J2EE的規范,在GlassFish中也沒有對應的實現,據說在將來的版本中考慮支持。GlassFish中目前提供的LifeCycleListener不能滿足該要求,它只能在GlassFish啟動和停止的時候去做工作,而且,采用了這種方式,等于又將我們的應用綁定在了GlassFish上。思前想后,想到了一個臨時的解決方案,雖然不能達到Weblogic的LCM的作用,但能滿足當前應用中的需求,就是采用在ear中加入一個web module,在web container啟動和停止的時候去完成這項工作。由于較長的一段時間沒有寫過Web應用了,對一些知識點已經遺忘了,眼前對于是采用Servlet的init和destroy來作為實現,還是采用ServletContextListener,有點不清楚他們之間確切的區別,只好重新作以復習了。
        下面先來看Servlet是如何工作的,Servlet的生命周期包含了四個階段:
        1、加載和實例化
        當servlet容器啟動時,或者在容器需要這個servlet來響應第一個請求時,創建servlet實例。因為容器是通過Java的反射API來創建servlet實例,調用的是servlet的默認構造方法,所以在編寫servlet的時候,不應該提供帶參數的構造方法。
        2、初始化
        在servlet實例化之后,容器將調用servlet的init方法初始化這個對象。初始化的目的是為了讓servlet對象在處理請求錢完成一些初始化的工作,每個servlet實例的init方法只被調用一次。在初始化期間,servlet實例可以使用ServletConfig對象從Web應用的配置信息(在web.xml中配置)中獲取初始化的參數信息。在初始化期間,如果發生錯誤,Servlet實例可以拋出ServletException或者UnavailableException來通知容器。ServletException用于指明一般的初始化失敗,例如沒有找到初始化參數;而UnavailableException用于通知容器該Servlet實例不可用。例如,數據庫服務器沒有啟動,數據庫連接無法建立,Servlet就可以拋出UnavailableException向容器指出它暫時或永久不可用。
        3、請求處理
        Servlet容器調用Servlet的service方法對請求進行處理。要注意的是,在service方法調用之前,init方法必須成功執行。在service方法執行期間,如果發生錯誤,Servlet實例可以拋出ServletException或者UnavailableException。如果UnavailableException指示了該實例永久不可用,Servlet容器將調用實例的destroy()方法,釋放該實例。
        4、服務終止
        當容器檢測到一個Servlet實例應該從服務中被移除的時候,容器就會調用實例的destroy方法。當需要釋放內存或者容器關閉時,容器就會調用Servlet實例的destroy方法。在destroy方法調用之后,容器會釋放這個Servlet實例,該實例隨后會被Java的垃圾收集器所回收,如果再次需要這個Servlet處理請求,Servlet容器會創建一個新的 Servlet實例。

        再看ServletContextListener。ServletContextListener接口能夠監聽ServletContext對象的生命周期,也就是監聽Web應用的生命周期。當Servlet容器啟動或終止Web應用時,會觸發ServletContextEvent事件,該事件由ServletContextListener來處理。在ServletContextListener 接口中定義了處ServletContextEvent事件的兩個方法:
        contextInitialized(ServletContextEvent event):當Servlet容器啟動Web應用時調用該方法。在調用完該方法之后,容器再對Filter初始化,并且對那些在Web應用啟動時就需要被初始化的Servlet進行初始化。 
        contextDestroyed(ServletContextEvent event):當Servlet容器終止Web應用時調用該方法。在調用該方法之前,容器會先銷毀所有的Servlet和Filter過濾器。
        因此我們可以得知,在Web應用啟動時,Servlet容器會先調用ServletContextListener的contextInitalized方法,再調用Servlet的init方法;當Web應用終止時,Servlet容器先調用Servlet的destroy方法,再調用ServletContextListener的contextDestroyed方法。由此可見,在Web應用的生命周期中,ServletContext對象是最早被創建,最晚被銷毀。