4.2.3 Servlet的调用过程
要运行一个Servlet程序,除了Servlet类和web.xml外,还需要一个Servlet引擎。Servlet的运行完全由Servlet引擎来控制和调度。Servlet引擎是一种容器程序,它负责管理和维护Servlet对象的生命周期。因此,Servlet引擎也被称为Servlet容器或Web容器。除了Servlet引擎外,还需要一个可以处理并发操作的服务端程序,在本书中使用的是Tomcat。由于很多Web服务器(如Tomcat)都将Servlet引擎和服务端程序集成在一起,因此,大多数时候也可以将Web服务器看作是Servlet引擎。因此,在本书中所指的Servlet引擎就是指Tomcat。由此可见,运行Servlet的三要素是Servlet类、web.xml和Servlet引擎。
Servlet引擎按着下面的流程来运行一个Servlet程序:
1. 在接收到客户端的某个HTTP请求后,Servlet引擎获得了一个URL,并对其进行分析。假设客户端请求的URL如下:
http://localhost:8080/demo/servlet/MyServlet
Servlet引擎从上述的URL中提取了“/demo”和“/servlet/MyServlet”。
2. 在<Tomcat安装目录>\conf\server.xml文件中的查找path属性值为“/demo”的<Context>元素(在这里只描述了一般的查找过程,实际上是先到<Tomcat安装目录>\webapps目录中去找demo目录),找到后,获得docBase属性值指定的Web应用程序的目录或war包。
3. 根据上一步找到的Web应用程序的具体位置,找到web.xml文件并读取相关的内容(实际上,这个文件在Tomcat启动时就已经加载了)。在获得这些信息后,将从URL中提取的“/servlet/MyServlet”和<servlet-mapping>元素中的<url-pattern>子元素值进行比较。如果发现相匹配的<url-pattern>元素,就可以获得相应的Servlet类。
4. 如果在上一步中获得了相应的Servlet类,Servlet引擎就会动态装载这个Servlet类,并创建个Servlet对象。
5. 在创建Servlet对象后,开始执行相应的方法。首先调用了init()方法,然后开始调用service()方法(通过调用service()方法,会根据客户端不同的HTTP请求调用相应的doXxx方法)。在调用service()方法时,Servlet引擎创建了HttpServletRequest和HttpServletResponse对象,这两个对象分别用于处理客户端的请求和向客户端发送响应信息。
6. 在Web应用程序被停止或重新启动时,Servlet引擎将卸载其中的Servlet。在这时,Servlet引擎将调用destroy方法。
需要对上面的流程做如下三点补充说明:
1. 对于不同Servlet的启动顺序可以由web.xml文件中的<servlet>元素的<load-on-startup>子元素决定。当这个元素的值是0或正整数时,数值大的Servlet先被装载。如果<load-on-startup>元素的值相同或为负数,则由Servlet引擎自己决定先装载哪个Servlet。
2. Servlet在装载后就常驻内存。因此,init方法只在Servlet装载时运行一次,而每一个Servlet在每一次被访问时都会调用自己的service方法。在调用service方法时,都会创建一个新的HttpServletRequest请求对象和HttpServletResponse响应对象。
3. 在默认情况下,当开发人员对Servlet进行了修改,除非重新启动Tomcat,否则Servlet引擎还是执行内存中的Servlet对象实例。如果想在Tomcat不重新启动的情况下感知Servlet的变化,可以通过<Context>元素的reloadable属性来设置,设置代码如下:
<Context path="/demo" docBase = "d:\demo" debug = "0" reloadable = "true" />
使用上面的设置后,Tomcat会监视classes和lib目录下的类是否改变,一但其中某个类改变,Tomcat就会重新装载Web应用,并在Tomcat控制台显示相关提示信息。