
3.2 Servlet基础
3.2.1 Servlet定义
Servlet是服务器端的Java应用程序,它用来扩展服务器的功能,可以生成动态的Web页面。Servlet与传统Java应用程序最大的不同在于:它不是从命令行启动的,而是由包含Java虚拟机的Web服务器进行加载。
Applet是运行于客户端浏览器的Java应用程序,Servlet与Applet相比较,有以下特点。
1.相似之处
(1)它们不是独立的应用程序,没有main方法。
(2)它们不是由用户调用,而是由另外一个应用程序(容器)调用。
(3)它们都有一个生命周期,包含init和destroy方法。
2.不同之处
(1)Applet运行在客户端,具有丰富的图形界面。
(2)Servlet运行在服务器端,没有图形界面。
造成这种差别的原因在于它们所肩负的使命不同。Applet目的是为了实现浏览器与客户的强大交互,因此需要丰富多样的图形交互界面;Servlet用于扩展服务器端的功能,实现复杂的业务逻辑,它不直接同客户交互,因此不需要图形界面。
Servlet最大的用途是通过动态响应客户端请求来扩展服务器功能。
3.2.2 Servlet工作流程
Servlet运行在Web服务器上的Web容器里。Web容器负责管理Servlet。它装入并初始化Servlet,管理Servlet的多个实例,并充当请求调度器,将客户端的请求传递到Servlet,并将Servlet的响应返回给客户端。Web容器在Servlet的使用期限结束时终结该Servlet。服务器关闭时,Web容器会从内存中卸载和除去Servlet。
Servlet的基本工作流程如下:
(1)客户端将请求发送到服务器。
(2)服务器上的Web容器实例化(装入)Servlet,并为Servlet进程创建线程。请注意,Servlet是在出现第一个请求时装入的,在服务器关闭之前不会卸载它。
注意:Servlet也可以配置为Web应用程序启动时自动装载。关于如何配置Servlet将在3.6节详细讲解。
(3)Web容器将请求信息发送到Servlet。
(4)Servlet创建一个响应,并将其返回到Web容器。Servlet使用客户端请求中的信息以及服务器可以访问的其他信息资源(如资源文件和数据库等)来动态构造响应。
(5)Web容器将响应返回客户端。
(6)服务器关闭或Servlet空闲时间超过一定限度时,调用destroy方法退出。
从上面Servlet的工作基本流程可以看出,客户端与Servlet间没有直接的交互。无论是客户端对Servlet的请求还是Servlet对客户端的响应,都是通过Web容器来实现的,这就大大提高了Servlet组件的可移植性。
下面对Servlet的工作基本流程进行详细说明。
1.Servlet装入和初始化
第一次请求Servlet时,服务器将动态装入并实例化Servlet。开发人员可以通过Web配置文件将Servlet配置成在Web服务器初始化时直接装入和实例化。Servlet调用init方法执行初始化。init方法只在Servlet创建时被调用,所以,它常被用来作为一次性初始化的工作,如装入初始化参数或获取数据库连接。
init方法有两个版本:一个没有参数,一个以ServletConfig对象作为参数。
2.调用Servlet
每个Servlet都对应一个URL地址。Servlet可以作为显式URL引用调用,或者嵌入在HTML中并从Web应用程序调用。
Servlet和其他资源文件(如JSP文件、静态HTML文本等)打包作为一个Web应用存放在Web服务器上。对于每个Web应用,都可以存在一个配置文件web.xml。关于Servlet的名称、对应的Java类文件、URL地址映射等信息都存放在配置文件web.xml中。当Web服务器接收到对URL地址的请求信息时,会根据配置文件中URL地址与Servlet之间的映射关系将请求转发到指定的Servlet来处理。
说明:自Java EE 6版本以来,Java EE规范推荐使用注解来配置Web组件,而不是使用配置文件web.xml。注解是内嵌在Java代码中的一种特殊标记,关于注解的使用本书后面的示例中会反复讲到。因此,在Java EE 6版本以上的Web应用中,也允许没有配置文件web.xml存在。
3.处理请求
当Web容器接收到对Servlet的请求,Web容器会产生一个新的线程来调用Servlet的service方法。service方法检查HTTP请求类型(GET、POST、PUT、DELETE等),然后相应地调用Servlet组件的doGet、doPost、doPut、doDelete等方法。如果Servlet处理各种请求的方式相同,也可以尝试覆盖service方法。GET请求类型与POST请求类型的区别在于:如果以GET方式发送请求,所带参数附加在请求URL后直接传给服务器,并可从服务器端的QUERY_STRING这个环境变量中读取;如果以POST方式发送请求,则参数会被打包在数据包中传送给服务器。
4.多个请求的处理
Servlet由Web容器装入,一个Servlet同一时刻只有一个实例,并且它在Servlet的使用期间将一直保留。当同时有多个请求发送到同一个Servlet时,服务器将会为每个请求创建一个新的线程来处理客户端的请求。
如图3-2所示,有两个客户端浏览器同时请求同一个Servlet服务,服务器会根据Servlet实例对象为每个请求创建一个处理线程。每个线程都可以访问Servlet装入时的初始化变量。每个线程处理它自己的请求。Web容器将不同的响应返回各自的客户端。

图3-2 Servlet对多个请求的处理
上述说明意味着Servlet的doGet方法和doPost方法必须注意共享数据和领域的同步访问问题,因为多个线程可能会同时尝试访问同一块数据或代码。如果想避免多线程的并发访问,可以设置Servlet实现SingleThreadModel接口,如下所示:
public class YourServlet extends HttpServlet implements SingleThreadModel { ... }
注意:使用SingleThreadModel接口虽然避免了多请求条件下的线程同步问题,但是单线程模式将对应用的性能造成重大影响,因此在使用时要特别慎重。
5.退出
如果Web应用程序关闭或者Servlet已经空闲了很长时间,Web容器会将Servlet实例从内存移除。移除之前Web容器会调用Servlet的destroy方法。Servlet可以使用这个方法关闭数据库连接、中断后台线程、向磁盘写入Cookie列表及执行其他清理动作。
注意:当Web容器出现意外而被关闭,则不能够保证destroy方法被调用。
通过上面Servlet工作流程的基本描述,对于Web容器的职责,可以归纳为以下两点:一是管理Servlet组件的生命周期,包括Servlet组件的初始化、销毁等;二是作为客户端与Servlet之间的中介,负责封装客户端对Servlet的请求,并将请求映射到对应的Servlet,以及将Servlet产生的响应返回给客户端。
3.2.3 Servlet编程接口
Java EE标准定义了Java Servlet API,用于规范Web容器和Servlet组件之间的标准接口。Java Servlet API是一组接口和类,主要由两个包组成:javax.servlet包含了支持协议无关的Servlet的类和接口;javax.servlet.http包括了对HTTP协议的特别支持的类和接口。如果希望详细了解Java Servlet API,可访问http://www.oracle.com/technetwork/java/index-jsp-135475.html下载Java Servlet API的详细文档。
所有的Servlet都必须实现通用Servlet接口或HttpServlet接口。通用Servlet接口类javax.servlet.GenericServlet定义了管理Servlet及它与客户端通信的方法;HttpServlet接口类javax.servlet.http.HttpServlet是继承了通用Servlet接口类的一个抽象子类。要编写在Web上使用的HTTP协议下的Servlet,通常采用继承HttpServlet接口的形式。下面以HttpServlet接口为中心,介绍与Servlet编程密切相关的几个接口,如图3-3所示。

图3-3 Servlet编程相关接口示意图
·HttpServletRequest代表发送到HttpServlet的请求。这个接口封装了从客户端到服务器的通信。它可以包含关于客户端环境的信息和任何要从客户端发送到Servlet的数据。
·HttpServletResponse代表从HttpServlet返回客户端的响应。它通常是根据请求和Servlet访问的其他来源中的数据动态创建生成的响应,如HTML页面。
·ServletConfig代表Servlet的配置信息。Servlet在发布到服务器上的时候,在Web应用配置文件中对应一段配置信息。Servlet根据配置信息进行初始化。配置信息的好处在于在Servlet发布时可以通过配置信息灵活地调整Servlet而不需要重新改动、编译代码。
·ServletContext代表Servlet的运行环境信息。Servlet是运行在服务器上的程序。为了与服务器及服务器上运行的其他程序进行交互,有必要获得服务器的环境信息。
·ServletException代表Servlet运行过程中抛出的意外对象。
·HttpSession用来在无状态的HTTP协议下跨越多个请求页面来维持状态和识别用户。维护HttpSession的方法有Cookie或URL重写。
·RequestDispatcher:请求转发器,可以将客户端请求从一个Servlet转发到其他的服务器资源,如其他Servlet、静态HTML页面等。
Java EE服务器必须声明支持的Java Servlet API的版本级别。随着Java EE技术的不断进步,Java Servlet API的版本也在不断更新,在Java EE 8标准规范中包含的Java Servlet API的版本为4.0。