4.3.3 init和destroy方法

优质
小牛编辑
126浏览
2023-12-01

init和destroy方法分别在Servlet容器建立Servlet对象和销毁Servlet对象时调用。而且这两个方法只在Servlet的生命周期里调用一次。在Servlet接口中定义了这两个方法,在GenericServlet类中提供了这两个方法的默认实现。init方法有一个ServletConfig类型的参数,可以通过这个参数获得配置信息(也就是在web.xml文件中配置的内容),关于ServletConfig接口的内容将在4.4节详细介绍。destroy方法一般用于在Servlet对象被销毁时释放一些全局的资源,如数据库连接、网络资源等。

init方法和destroy方法的定义如下:

public void init(ServletConfig config) throws ServletException;

public void destroy();

有很多开发人员在编写Servlet类时往往直接覆盖了init方法来完成初始化工作。这么做一般没什么问题。但却将GenericServlet中init方法的默认实现覆盖了。先看看GenericServlet类中相关方法的实现代码:

public abstract class GenericServlet
    implements Servlet, ServletConfig, java.io.Serializable
{
    private transient ServletConfig config;
    //  获得ServletConfig对象
    public ServletConfig getServletConfig()
{
        return config;
    }
    //  实现Servlet接口中的init方法
    public void init(ServletConfig config) throws ServletException
{
        this.config = config;
    this.init();
    }
    //  GenericServlet类中提供了空参数的init方法
    public void init() throws ServletException
{
    }
}

从上面的代码可以看出,带参数的init方法的第一行将config参数值赋给了类变量config。并且getServletConfig方法是通过config变量来返回ServletConfig对象的。如果开发人员覆盖了带参数的init方法,而又未调用super.init(config)语句,那么通过getServletConfig方法就无法再获得ServletConfig对象了,虽然开发人员也可以在Servlet类的init方法中将ServletConfig对象保存起来,但这实在是多此一举。当然,如果即不调用super.init(config)语句,也不保存ServletConfig对象,那么这个ServletConfig对象将会丢失,也就是说,在service、doXxx等方法中将无法获得并使用ServletConfig对象了。为了避免这个尴尬,在GenericServlet类中提供了一个不带参数的init方法,并且在带参数的init方法中调用该init方法,如上面的代码所示。

如果开发人员在Servlet类中覆盖这个不带参数的init方法,那么就仍然可以通过getServletConfig方法来获得ServletConfig对象。因此,我建议尽量在Servlet类中覆盖不带参数的init方法来初始化Servlet,如果要在init方法中使用ServletConfig对象,可以使用getServletConfig方法来获得ServletConfig对象。

下面的例子演示了init和destroy方法在Servlet的生命周期中的调用情况。

1. 实例说明

在本例中的Servlet类中覆盖了init和destroy方法。在第一次访问Servlet时,将调用init方法。然后通过重新发布Servlet的方式使Servlet引擎调用该Servlet类的destroy方法。然后再次访问这个Servlet,Servlet引擎再次调用init方法。最后通过停止Tomcat的方式使Servlet引擎再次调用destroy方法。也就是说,在本例中,Servlet引擎会调用两次init方法和两次destroy方法。

2. 编写Servlet类

本例中Servlet类的实现代码如下:

public class InitDestroyServlet extends HttpServlet
{
    //  覆盖无参数的init方法
    public void init() throws ServletException
    {
        System.out.println("init方法被调用!");
    }
    //  覆盖destroy方法
    public void destroy()
    {
        System.out.println("destroy方法被调用");
    }
    //  处理客户端的HTTP请求
    protected void service(HttpServletRequest request,
            HttpServletResponse response) throws ServletException, IOException
    {
        response.setContentType("text/html;charset=UTF-8");
        response.getWriter().println("测试init和destroy方法");
    }
}


下面的InitDestroyServlet类的配置代码: 

<servlet>
 <servlet-name>InitDestroyServlet</servlet-name>
 <servlet-class>chapter4.InitDestroyServlet</servlet-class>
 </servlet>
 <servlet-mapping>
 <servlet-name>InitDestroyServlet</servlet-name>
 <url-pattern>/InitDestroyServlet</url-pattern>
 </servlet-mapping>

3. 通过测试来观察init和destroy方法的调用情况

在IE地址栏中输入如下的URL:

http://localhost:8080/demo/InitDestroyServlet

这时在控制台中将输出“init方法被调用!”的信息。这时在Eclipse中稍微修改一下InitDestroyServlet类(可以加一个空格,并保存),这时Eclipse会自动重新发布Web应用,在控制台中就会输出“destroy方法被调用”的信息。在等待Web应用重新发布成功后,再次访问上面的URL,并且在Eclipse中停止Tomcat,这时,Servlet引擎会再次调用Servlet类的destroy方法。以上测试过程输出的信息如图4.4所示。

04

图4.4 init和destroy方法的调用情况

4. 程序总结

从本例可以看出,Servlet类的destroy方法会在Web应用重新发布时,或Web服务端(如Tomcat)停止时调用。