可参考博文 超文本传输协议HTTP。
Servlet(Server Applet)是Java Servlet 的简称,称为小服务程序或服务连接器,用Java 编写的服务器端程序,主要功能在于交互式地浏览和修改数据,生成动态Web 内容。
从原理上讲,Servlet 可以响应任何类型的请求,但绝大多数情况下Servlet 只用来扩展基于HTTP 协议的Web 服务器。HTTP 定义的与服务器交互的方法有GET、POST、PUT和DELETE 等,其中最基本的是GET 与POST。HTTP-GET 与HTTP-POST 是使用HTTP 的标准协议动词,用于编码和传送变量名/变量值对参数,并使用相关的请求(Request)语义。每个HTTP-GET 与HTTP-POST 都由一系列的HTTP 请求头组成,这些请求头定义了客户端从服务器上请求了什么,而响应(Response)则是由一系列HTTP 应答头和应答数据组成,如果请求成功,则返回应答数据。
其中GET 与POST 的主要区别如下
狭义的Servlet是指Java语言实现的一个接口,广义的Servlet是指任何实现了这个Servlet接口的类,一般情况下,人们将Servlet理解为后者。下面是Servlet 架构图。
Servlet 与CGI(Common Gateway Interfece,公共网关接口)都是服务端组件,通常情况下可以实现相同的效果。但是与CGI 相比,Servlet 有以下的相关优势
SUN 首先发展出 Servlet,其功能比较强劲,体系设计也很先进,只是,它输出HTML 语句还是采用了老的 CGI 方式,是一句一句输出,所以,编写和修改 HTML 非常不方便。
Java Server Pages(JSP)是一种实现普通静态HTML 和动态 HTML 混合编码的技术,JSP 并没有增加任何本质上不能用 Servlet 实现的功能。但是,在 JSP 中编写静态HTML 更加方便,不必再用 println语 句来输出每一行 HTML 代码。更重要的是,借助内容和外观的分离,页面制作中不同性质的任务可以方便地分开:比如,由页面设计者进行 HTML设计,同时留出供 Servlet 程序员插入动态内容的空间。
JSP 在首次被访问的时候会被服务器转换为Servlet ,在以后的运行中,容器直接调用这个Servlet,而不再访问JSP 页面。所以来说JSP 的本质就是Servlet。
总而言之,JSP 的本质是Servlet ,由于在Servlet 中开发HTML 代码不方便,所以JSP 应运而生。我们一般使用JSP 作数据页面展示,使用Servlet 来处理客户端与服务端的交互。
Servlet 接口:定义了一个servlet 应该具有的方法(如init、service 与destroy 方法等),所有的Servlet都应该直接或间接实现此接口。
GenericServlet 抽象类:通用Servlet,对Servlet 接口的默认实现,这是一个抽象类,其中的大部分方法都做了默认实现,只有service 方法是一个抽象方法需要继承者自己实现。
HttpServlet 抽象类:对HTTP 协议进行了优化的Servlet,继承自GenericServlet 类,并且实现了其中的service 抽象方法,默认的实现中判断了请求的请求方式,并根据请求方式的不同分别调用不同的doXXX() 方法。通常我们编写Servlet 直接继承该抽象类即可。
下面就结合源码来看一下HttpServlet 中service() 方法的实现(代码逻辑很清晰就不再做具体的分析)
protected void service(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
String method = req.getMethod(); //返回一个字符串形式的请求方式
if (method.equals(METHOD_GET)) { //如果当前客户端发起的是GET 方式的请求,就调用doGet() 方法
long lastModified = getLastModified(req);
if (lastModified == -1) {
// servlet doesn't support if-modified-since, no reason
// to go through further expensive logic
doGet(req, resp);
} else {
long ifModifiedSince = req.getDateHeader(HEADER_IFMODSINCE);
if (ifModifiedSince < (lastModified / 1000 * 1000)) {
// If the servlet mod time is later, call doGet()
// Round down to the nearest second for a proper compare
// A ifModifiedSince of -1 will always be less
maybeSetLastModified(resp, lastModified);
doGet(req, resp);
} else {
resp.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
}
}
} else if (method.equals(METHOD_HEAD)) {
long lastModified = getLastModified(req);
maybeSetLastModified(resp, lastModified);
doHead(req, resp);
} else if (method.equals(METHOD_POST)) { //如果客户端发起的是POST方式的请求,调用doPost() 方法
doPost(req, resp);
} else if (method.equals(METHOD_PUT)) {
doPut(req, resp);
} else if (method.equals(METHOD_DELETE)) {
doDelete(req, resp);
} else if (method.equals(METHOD_OPTIONS)) {
doOptions(req,resp);
} else if (method.equals(METHOD_TRACE)) {
doTrace(req,resp);
} else {
String errMsg = lStrings.getString("http.method_not_implemented");
Object[] errArgs = new Object[1];
errArgs[0] = method;
errMsg = MessageFormat.format(errMsg, errArgs);
resp.sendError(HttpServletResponse.SC_NOT_IMPLEMENTED, errMsg);
}
}
Servlet 运行于服务器上的Web 容器中(比如Tomcat 与Jboss 等)。应用服务器中用于管理Java 组件的部分被称为Servlet 容器。当Servlet 被部署在应用服务器以后,由容器控制Servlet 的生命周期。Servlet 在第一次被请求的时候加载和实例化。Servlet 一旦被加载,当响应结束后会一直驻留在内存中等待下一次请求,直至应用服务器关闭或者重新启动。所以第一次访问Servlet 花费的时间要大于以后访问该Servlet 所用的时间。当容器作内存回收时,Servlet 可能会被删除。
1. 加载Servlet 类,创建该类的实例。每一个用户都会产生一个新的线程(所以说Servlet 是线程不安全的)。
2. Servlet 通过init() 方法进行初始化。
3. Servlet 调用service(req,resp) 方法,根据请求方式调用对应的do×××() 方法,来处理客户端的请求。
4. Servlet 通过destroy() 方法终止。
5. Servlet 被JVM 的垃圾回收机制收集。
为了更好的理解,这里通过一个例子来具体讲述其中的过程。
新建一个Servlet,如下(当客户端请求该Servlet 时,输出一个表情符号)
package com.jas.test;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
public class ServletTest extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.getWriter().write("O(?_?)O~");
}
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doPost(request,response);
}
}
在web.xml 中配置上面Servlet 的相关信息,如下
PS:Tomcat 7 及以上的版本不需要再做相应配置,通过@WebServlet(“/XXX”) 注解就可以实现配置文件的作用。这里为了演示效果仍然使用配置文件的形式。
<servlet>
<servlet-name>helloservlet-name>
<servlet-class>com.jas.test.ServletTestservlet-class>
servlet>
<servlet-mapping>
<servlet-name>helloservlet-name>
<url-pattern>/hellourl-pattern>
servlet-mapping>
调用过程分析如下(HTTP 请求报文与响应报文数据摘自IE 浏览器),过程中省略了Servlet 实例化的过程。
参考资料:
《JavaEE编程及应用开发》