[转]通俗易懂Tomcat中Servlet的生命周期

我在上一篇文章里详细的介绍了 HTTP协议工做的流程,其中最重要的就是如何理解 HTTP请求头和HTTP响应头,如今在这里再来详细的说明Tomcat 容器(即Servlet 容器)究竟是如何 管理 Servlet的,Servlet 的生命周期究竟是如何进行的,其中与 Tomcat 容器的交互过程,相信你们只要看懂下面的分析,必定会真正理解 Servlet 生命周期的。web

其中因此引用的实例说明均来自本人本身的配置,如下全部例子均只实现了 doGet( ) 方法。apache

一. Tomcat 是如何 加载 Servlet 的,期间到底发生了什么。(Servlet 的初始化)tomcat

首先,咱们 在 C:\apache-tomcat-5.5.20\webapps\ROOT\WEB-INF 目录下找到 web.xml 配置文件,这个 配置文件实际上起到的最直接的做用就是 管理 Servlet 。里面我先写两个 <servlet> 和<serlvet-mapping>服务器

<servlet>
 <servlet-class>RequRepon</servlet-class>
 <servlet-name>reqrep</servlet-name>
</servlet>
多线程

<servlet-mapping>
 <servlet-name>reqrep</servlet-name>
 <url-pattern>/accp/reqrep</url-pattern>
</servlet-mapping>
app

<servlet>
 <load-on-startup>0</load-on-startup>                                                  -------------tomcat 服务一启动就会加载
   <init-param>
  <param-name>num</param-name>
  <param-value>10000</param-value>
   </init-param>
       <servlet-name>www</servlet-name>
    <servlet-class>MyServlet</servlet-class>
   </servlet>
webapp

   <servlet-mapping>
       <servlet-name>www</servlet-name>
    <url-pattern>/accp/myservlet</url-pattern>
   </servlet-mapping>
url

在 C:\apache-tomcat-5.5.20\webapps\ROOT\WEB-INF\classes  路径下放好我已经通过编译后的两个 Servlet  .class 文件 ,一个是 MyServlet,一个是 RequReponspa

启动 C:\apache-tomcat-5.5.20\bin 路径下 startup.bat ,tomcat 开始启动。.net

这个时候咱们会发如今 Tomcat 命令控制台上出现了 一句话 ,

MyServlet 中的 init () 方法被调用了一次!

其实我在 MyServlet ,和 RequRepon 都写了 ---####的 init () 方法被调用了一次!可是RequRepon 中的init()并无被调用,缘由就在于 web.xml 中

<servlet>
 <load-on-startup>0</load-on-startup>                                                  -------------tomcat 服务一启动就会加载
   <init-param>
  <param-name>num</param-name>
  <param-value>10000</param-value>
   </init-param>
       <servlet-name>www</servlet-name>
    <servlet-class>MyServlet</servlet-class>
   </servlet>

就通知了 Tomcat 在它的服务一启动的时候 ,就要去加载 所对应的 Servlet-class   MyServlet 这个类,0表明优先级别,随后是 1. 2. 3. .4.... 0的优先级别最高。Tomcat 首先把这些类加载并实例化,保存在本身的Servlet 容器池中,之后若是有请求,直接今后容器池中取出来,处理相应的请求。

RequRepon  没有被加载没有关系,咱们在地址栏输入 http://localhost:8080/accp/reqrep

这个时候出现:注意最下面的两行

RequRepon 中的 init( ) 方法不只被调用了,而且其 doGet( ) 方法也被调用了!

那么这是为何呢?缘由就是虽然 RequRepon  首先被加载到 Tomcat 容器中,可是一旦有来自客户端的请求,Tomcat 会解析这个请求 URL 找到指定的 Servlet 类,再加载同时处理请求,因此就会调用它的 doGet( )方法

<servlet>
 <servlet-class>RequRepon</servlet-class>
 <servlet-name>reqrep</servlet-name>
</servlet>

<servlet-mapping>
 <servlet-name>reqrep</servlet-name>
 <url-pattern>/accp/reqrep</url-pattern>                            

</servlet-mapping>

根据请求 http://localhost:8080/accp/reqrep     

找到 <servlet-name> reqrep 

根据 reqrep   找到对应的 <servlet-class> RequRepon  加载并初始化

这个时候咱们再作这样的一个动做,把 C:\apache-tomcat-5.5.20\webapps\ROOT\WEB-INF\classes 中的两个类删除掉,在 http://localhost:8080/accp/reqrep          或者  http://localhost:8080//accp/myservlet

会发现 Tomcat 中 这两个类的 doGet( ) 方法仍然被实现了,也就说来自于客户端的请求他们已经收到了,并调用了doGet( ) 方法进行了处理。

再来总结以上的内容,就是Servlet 如何被加载的。

1. Tomcat 加载 Servlet 而且实例化,有两种方法:

一种是根据 web.xml中  <load-on-startup>0</load-on-startup>  的配置,在Tomcat 一启动的时候就加载,并同时实例化,并立刻调用 其 init( ) 方法,完成初始化过程。

第二种就是动态的加载,根据客户端的请求 URL 如: http://localhost:8080/accp/reqrep     中的accp/reqrep     

去在 web.xml 中寻找指定的 Servlet 类,加载它并实例化,立刻调用其 init( ) 方法完成初始化,因为是来自客户端的一个请求,那么天然要 调用 doGet( ) 方法来处理请求。

2. Servlet 的初始化 ,即init( ) 方法是优于其它全部方法以前的,在处理任何响应以前就会调用的,而且在一个生命周期中有且只有一次!

3. Tomcat 一旦加载 Servlet ,实例化,就将其保存在内存中, 之后无论多少次来自于客户端的请求都是由保存在Tomcat 容器池(即内存)里面的 Servlet 实例来处理,它不是开启了一个进程,而是实现了多线程操做,这也就是为何要引用 Servlet 而不用 CGI 的优势。这个证据就是 我已经在 C:\apache-tomcat-5.5.20\webapps\ROOT\WEB-INF\classes  路径下删除了 这两个 Servlet  .class 文件,可是请求同样处理,这就能证实,Tomcat 完成类加载是将他们保存在内存中,以便之后使用,效率很高。

二.doGet( ) 和 doPost( ) 究竟是怎么样来的,为何没有 Service( ) 方法,里面的流程是什么?

上面只说明了 init( ) 有关的东西,如今来讲 doGet( ) 和 doPost( ) ,那么这个要和个人另外一篇文章 关于 HTTP 请求头和HTTP 响应头结合起来看,会有很好的效果的。

http://blog.csdn.net/lvpin/archive/2007/06/09/1645770.aspx

 通俗易懂客户端与服务器端交互原理(HTTP数据请求与HTTP响应,包括Servlet部分)

当Tomcat 容器收到一个消息,用户请求一个Servlet ,那么就生成了一个响应头,其实就是 HttpServletRequest 对象,根据 url 指定的 Servlet ,Tomcat 就让此 Servlet 来处理这个请求。

那么咱们在 Java程序中其实实现的就是 HttpServelt ,重写了 doGet( ) 或者doPost( ) 方法,就能够处理这个请求了。可是 doGet( ) 或者 doPost( ) 方法是由 Service( ) 来调用的,咱们怎么不重写Service( ) 方法呢?那是由于HttpServlet 继承了GenericServlet ,而GenericServlet 实现了Servlet 接口。在其中的一个类中,它的 Service( ) 其实就已经解析了 来自于 Http 请求头的内容,根据请求行的 method  来决定调用 doGet( ) 或者 doPost( ) 方法,同时把 HttpServletRequest 和 HttpServletResponse 以参数的形式传递给 doGet( ) 或者doPost( ),来进行咱们的业务处理。

若是重写 Service( ) 方法,那么里面的不少工做可能就须要咱们完成,其实这并不须要,咱们只须要重写 doGet( ) 或者 doPost(  ) 方法就能够了。这个重写的动做就是Servlet 生命周期中的 Service( ) 方法,里面调用了 doGet( ) 或者doPost( ) 方法。

三.处理请求结束,生成响应回发,销毁实例

处理请求结束,生成响应回发,这个在我上面所提到的文章里已经讲的很清楚了。

至于销毁实例 ,完成 destroy( ) 动做,一是只要把 tomcat 服务关闭就能够了。另外还有一种能实现 destroy( ) 的方法,多是 Tomcat 里面的一些小BUG ,我正在找证据,已经发现一些端倪,今天有事暂时不写。重点就是前面的内容了。

相关文章
相关标签/搜索