相册

Servlet 的生命周期

每个servlet在创建的时候只构建一个实例,每个用户请求时其实是与该servlet的新的线程在交互,
该线程将用户的提交根据不同的类型分发给doGet或doPost方法进行处理。

当servlet初次创建实例时,它自身的init方法会被激活,有的朋友会问为什么我们前面编写的servlet
没有init方法,那是因为init方法已经存在于GenericServlet类中,默认是调用该父类的init方法。

init方法是放置通用代码的地方,你可以理解为初始化设置(有点像类的静态变量或方法那个意思,这是为了便于理解)。

针对每个不同客户端请求该servlet服务,都会单独创建一个线程,然后调用前面唯一构建实例的服务(service)方法,
多个并发的请求将有多个线程同时调用service方法。然后service方法再调用doGet,doPost或者其它doXxx方法,
这个调用取决于获取用户的HTTP请求的类型。最终当运行容器要卸载该servlet,它会调用destory方法来完成收尾工作。

service方法

服务器每次接受到servlet请求,都会产生一个新的线程,调用构建实例的service方法,有的朋友又在好奇这个service
方法又在哪里,它就在HttpServlet类中,自己可以去看看servlet-api的源代码。service方法检查HTTP请求的类型
(GET,POST,PUT,DELETE…)然后分别调用doGet,doPost,doPut,doDelete等方法。
Get和Post的请求属于html基本知识,这里不再类述。其它的http请求由客户端定制产生,如果你想对post和get进行相
同的处理,我们只需要让doPost调用doGet方法即可,反过来也可以。代码如下所示:

public void doGet(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException {
// Servlet code
}
public void doPost(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}

doGet,doPost和doXxx方法

大部分时间我们只需要关注GET和POST方法,其它方法还有doDelete,doPut,doOptions和doTrace。
还有一个doHead,有时为了更快的生成对HEAD请求的响应,客户端只需要HTTP报头,不需要用构建实际的客户端输出,则
我们会实现doHead方法。

init方法

init方法执行servlet初始化工作,我们可以在创建servlet实例时,初始化一些共用的任务。它只在创建实例时被初始化
一次,然后后面客户端请求的每个线程并不再调用该方法。

常规初始化

常规初始化会创建或载入servlet生命周期内用到的一些数据,或者执行某些计算。这些行为只需执行一次。
下面的例子 将是很好的演示:

package com.connove.action;

import java.io.IOException;
import java.io.PrintWriter;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * Servlet implementation class HelloServlet
 */

public class HelloServlet extends HttpServlet {
  private static final long serialVersionUID = 1L;
  private long modTime;
  private int[] numbers=new int[10];
  /**
   * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse
   *      response)
   */

  protected void doGet(HttpServletRequest request,
      HttpServletResponse response) throws ServletException, IOException {
    response.setContentType("text/html");
    PrintWriter out = response.getWriter();
    String docType = "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0 "
        + "Transitional//EN\">\n";
    out.println(docType + "<HTML>\n"
        + "<HEAD><TITLE>Hello</TITLE></HEAD>\n"
        + "<BODY BGCOLOR=\"#FDF5E6\">\n" + "<H1>Hello</H1><ul>\n");
    for(int i=0;i<numbers.length;i++)
      out.println("<ol>"+numbers[i]+"</ol>");
    out.println("</ul></BODY></HTML>");
    out.close();
  }

  @Override
  protected long getLastModified(HttpServletRequest req) {
    return modTime;
  }

  @Override
  public void init() throws ServletException {
    modTime=System.currentTimeMillis()/1000*1000;
    for(int i=0;i<numbers.length;i++)
      numbers[i]=randomNum();
  }

  @Override
  protected void service(HttpServletRequest req, HttpServletResponse res)
      throws ServletException, IOException {
    // TODO Auto-generated method stub
    super.service(req, res);
  }

  /**
   * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse
   *      response)
   */

  protected void doPost(HttpServletRequest request,
      HttpServletResponse response) throws ServletException, IOException {
    doGet(request, response);
  }
 
  private int randomNum() {
    return (int)(Math.random()*100);
  }
}

这是servlet的运行结果,可以看到一旦servlet创建实例,针对不同的请求,运行结果完全一样,
除非你重新创建该servlet。

初始化参数

这个我们经常用到的作为项目部署时初始化的参数,这个参数通过web.xml中的init-param来初始化一些数据库连接或者
动态类等等,我们以一个例子来说明:
先是web.xml中的servlet配置。

...
  <servlet>
    <description></description>
    <display-name>HelloServlet</display-name>
    <servlet-name>HelloServlet</servlet-name>
    <servlet-class>com.connove.action.HelloServlet</servlet-class>
    <init-param>
      <param-name>token</param-name>
      <param-value>123456</param-value>
    </init-param>
  </servlet>
  <servlet-mapping>
    <servlet-name>HelloServlet</servlet-name>
    <url-pattern>/hi</url-pattern>
  </servlet-mapping>
...

接着是servlet中的java代码。

//...
  public void init() throws ServletException {
    int token=Integer.valueOf(getServletConfig().getInitParameter("token"));
    System.out.println(token);
    modTime=System.currentTimeMillis()/1000*1000;
    for(int i=0;i<numbers.length;i++)
      numbers[i]=randomNum();
  }
//...

访问一下该servlet,可以看到在控制台输出了xml配置中token的值,我们还可以在xml中做更多的初始化值设置。
后面会再讲到。

destroy方法

web容器卸载载入的servlet实例之前,会调用servlet的destroy方法,该方法会关闭数据库链接、停止已运行的
线程…,执行其它清理工作。一般我们不需要实现重载该方法,父类已经帮我们做了相应的工作。

One thought on “Servlet 的生命周期

发表评论