最近在做将公司项目从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对象是最早被创建,最晚被销毁。