Servlet的全称是 Server Applet,顾名思义,就是用 Java 编写的服务器端程序。
Servlet 是一个 Java Web开发标准,狭义的Servlet是指Java语言实现的一个接口,广义的Servlet是指任何实现了这个Servlet接口的类,一般情况下,人们将Servlet理解为后者。
其主要功能在于:交互式地浏览和修改数据,生成动态Web内容。
Java Web 应用程序中所有的请求-响应都是由 Servlet 来完成的。Servlet 并没有
Web 开发技术主要是从静态网页技术到动态网页技术的变迁。
由于本文主要介绍 Java Web 开发技术,所以对其他语言的 Web 技术不做介绍。
Java Web 开发的大致发展历程如下:静态HTML –> CGI –> Servlet –> JSP
至于Spring、Struts等著名的框架则是在这些技术基础上的最佳编程实践。
早期的Web 开发只能提供静态的 HTML 页面。这样的模式显然存在很多弊端:不利于系统扩展,不利于和用户之间进行交互。于是,有了动态页面技术(如大家熟悉的JSP、ASP、PHP等等)。
CGI (Common Gateway Interface,公共网关接口)是最重要的 Web 技术之一。它是最早的动态页面技术。
CGI 是外部应用程序与 Web 服务器之间的接口标准。
绝大多数的CGI程序被用来解释处理来自表单的输入信息: CGI 允许服务器调用外部程序来处理输入信息,并将相应的输出反馈给浏览器。CGI程序使网页具有交互功能。
注:最流行的CGI 语言是 Perl 和Shell 脚本,但是也可以使用 C、C++ 以及Java 等语言来编写。
CGI 解决了静态页面不利于交互的问题,但其自身也存在缺陷:
l 需要为每个请求启动一个操作 CGI 程序的系统进程。如果请求频繁,会带来很大的系统开销。
如果用Java编写 CGI,除了需要为每个请求启动一个系统进程外,还要在进程中启动一个 JVM ,这将十分低效。
l 需要重复编写处理网络协议的代码,非常耗时。
知道了 Java 编写 CGI 的不足。我们不禁要问,如果有办法可以只运行一个系统进程和一个 JVM ,岂不是能大大减少开销吗?
Servlet 正是为此应运而生。
与传统的 CGI 技术相比,Servlet的优势在于:
l 传统的 CGI 中,每个请求都要启动一个新的进程;而在 Servlet 中,每个请求由一个轻量级的 Java 线程处理。
l 传统的 CGI 中,如果有 N 个并发的对同一个 CGI程序的请求,则该CGI程序的代码在内存中重复装载了 N 次;而对于 Servlet,处理请求的是 N 个线程,只需要一份 Servlet 类代码。
Servlet运行于支持Java的应用服务器中。从原理上讲,Servlet可以响应任何类型的请求,但绝大多数情况下Servlet只用来扩展基于HTTP协议的Web服务器。
JSP(Java Server Page)是一种实现静态HTML 和动态 HTML 混合编码的技术,它是Servlet API 的一个扩展。
Servlet 生命周期可被定义为从创建直到毁灭的整个过程。以下是 Servlet 遵循的过程:
Servlet 通过调用 init () 方法进行初始化。
Servlet 调用 service() 方法来处理客户端的请求。
Servlet 通过调用 destroy() 方法终止(结束)。
最后,Servlet 是由 JVM 的垃圾回收器进行垃圾回收的。
如下图:
执行流程为:
第一个到达服务器的 HTTP 请求被委派到 Servlet 容器。
Servlet 容器在调用 service() 方法之前加载 Servlet。
然后 Servlet 容器处理由多个线程产生的多个请求(GET、POST 等类型),每个线程执行一个单一的 Servlet 实例的 service() 方法。service() 会根据请求类型分发到对应的方法中去处理。
init 方法被设计成只调用一次。它在第一次创建 Servlet 时被调用,在后续每次用户请求时不再调用。因此,它是用于一次性初始化,就像 Applet 的 init 方法一样。
Servlet 创建于用户第一次调用对应于该 Servlet 的 URL 时,但是您也可以指定 Servlet 在服务器第一次启动时被加载。
当用户调用一个 Servlet 时,就会创建一个 Servlet 实例,每一个用户请求都会产生一个新的线程,适当的时候移交给 doGet 或 doPost 方法。init() 方法简单地创建或加载一些数据,这些数据将被用于 Servlet 的整个生命周期。
service() 方法遵循 HTTP 协议标准,负责将 HTTP 请求分发给对应类型的处理方法。
Servlet 容器(即 Web 服务器)调用 service() 方法来处理来自客户端(浏览器)的请求,并把格式化的响应写回给客户端。
每次服务器接收到一个 Servlet 请求时,服务器会产生一个新的线程并调用服务。service() 方法检查 HTTP 请求类型(GET、POST、PUT、DELETE 等),并在适当的时候调用 doGet、doPost、doPut,doDelete 等方法。
注意:service 方法不需要覆写。
GET请求来自于一个 URL 的正常请求,或者来自于一个未指定 METHOD 的 HTML 表单,它由 doGet() 方法处理。
POST请求来自于一个特别指定了 METHOD 为 POST 的 HTML 表单,它由 doPost() 方法处理。
destroy() 方法只会被调用一次,在 Servlet 生命周期结束时被调用。destroy() 方法可以让您的 Servlet 关闭数据库连接、停止后台线程、把 Cookie 列表或点击计数器写入到磁盘,并执行其他类似的清理活动。
在调用 destroy() 方法之后,servlet 对象被标记为垃圾回收。
就像任何其他的 Java 程序,需要通过使用 Java 编译器 javac 编译 Servlet,在编译 Servlet 应用程序后,将它部署在配置的环境中以便测试和运行。
必要条件:
JDK (Java Development Kit)
下载地址:http://www.oracle.com/technetwork/java/javase/downloads/index.html
Tomcat
HelloWorld.java
package demo; import java.io.*; import javax.servlet.*; import javax.servlet.http.*; publicclass HelloWorld extends HttpServlet { privatestaticfinallongserialVersionUID = 1L; private String message; publicvoid init() throws ServletException { message = "Hello World\n"; } publicvoid doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // 设置响应内容类型 response.setContentType("text/html"); // 实际的逻辑是在这里 PrintWriter out = response.getWriter(); out.println("<h1>" + message + "</h1>"); } publicvoid destroy() { // Do nothing } } |
---|
默认情况下,Servlet 应用程序位于路径 <Tomcat-installation-directory>/webapps/ROOT 下。
将以上 Servlet 代码编译后产生的class文件放在 <Tomcat 安装目录>/webapps/ROOT/WEB-INF/classes 中。
注意:需要保持代码的包(package)路径。
上例中的代码放在demo 包下,classes 下也需要保持路径一致,即 <Tomcat 安装目录>/webapps/ROOT/WEB-INF/classes/demo
下一步,是如何让服务器识别Servlet。
在web.xml中添加以下内容,然后将web.xml 文件放在 <Tomcat 安装目录>/webapps/ROOT/WEB-INF/web.xml。
web.xml
<servlet> <servlet-name>HelloWorld</servlet-name> <servlet-class>demo.HelloWorld</servlet-class> </servlet> <servlet-mapping> <servlet-name>HelloWorld</servlet-name> <url-pattern>/HelloWorld</url-pattern> </servlet-mapping> |
---|
(1)<servlet>
<servlet>标签用于配置 Servlet 类信息。
<servlet-name>是 Servlet 的标识,必须保证在整个xml 中唯一;
<servlet-class>是这个 Servlet 对应的类名。
(2)<servlet-mapping>
<servlet-mapping>标签用于配置Servlet 的访问路径。
<servlet-name> 需要和<servlet>中的<servlet-name>保持一致;
<servlet-name>指定访问路径。
做完以上工作,在<Tomcat 安装目录>/bin 目录下执行 startup.bat 或 startup.sh。
在浏览器中输入网址:http://localhost:8080/HelloWorld
输出结果:
Web 程序部署在 Tomcat 的 /webapps 下面。一个 webapps 文件夹可以部署多个不同的 Web 应用,例如 webapps/web1、webapps/web2,访问网址时分别为http://localhost:8080/web1、http://localhost:8080/web2。这两个不同的Web应用分别称为两个Context,路径/web1、/web2也称为上下文路径。
如果不适用上下文路径,Web 程序需放到webapps/ROOT 下面。ROOT 文件夹下的程序使用http://localhost:8080/ 访问。
按照Servlet 规范,Web 程序有自己特定的结构,部署时必须按照这样的结构部署。
文件夹 | 描述 |
---|---|
/ | Web 应用根目录 |
/WEB-INF/ | Tomcat 会隐藏该文件夹下的所有文件和文件夹,保护他们不能通过浏览器直接访问。 |
/WEB-INF/web.xml | web.xml 文件。Web 程序最主要的配置文件。 |
/WEB-INF/classes/ | class 类文件都放在该文件夹下面,包括 Servlet 类。 |
/WEB-INF/lib/ | jar 文件都放在该文件夹下面。 |