Servlet简介
Servlet是JavaWeb应用中最核心的组件。Servlet运行在Servlet容器中,能够为各种各样的客户请求提供相应服务。Servlet可以轻而易举地完成以下任务:
- 动态生成HTML文档。
- 把请求转发给同一个Web应用中的其他Servlet组件。
- 把请求转发给其他Web应用中的其他Servlet组件。
- 读取客户端的Cookie,以及向客户端写入Cookie。
- 访问其他服务器资源(如数据库或基于Java的应用程序)。
Servlet生命周期、工作原理
- Servlet 生命周期:Servlet 加载—>实例化—>服务—>销毁。
- init():在Servlet的生命周期中,仅执行一次init()方法。它是在服务器装入Servlet时执行的,负责初始化Servlet对象。可以配置服务器,以在启动服务器或客户机首次访问Servlet时装入Servlet。无论有多少客户机访问Servlet,都不会重复执行init()。
- service():它是Servlet的核心,负责响应客户的请求。每当一个客户请求一个HttpServlet对象,该对象的Service()方法就要调用,而且传递给这个方法一个“请求”(ServletRequest)对象和一个“响应”(ServletResponse)对象作为参数。在HttpServlet中已存在Service()方法。默认的服务功能是调用与HTTP请求的方法相应的do功能。
- destroy(): 仅执行一次,在服务器端停止且卸载Servlet时执行该方法。当Servlet对象退出生命周期时,负责释放占用的资源。一个Servlet在运行service()方法时可能会产生其他的线程,因此需要确认在调用destroy()方法时,这些线程已经终止或完成。
Tomcat 与 Servlet 是如何工作的:
步骤:
- Web Client 向Servlet容器(Tomcat)发出Http请求
- Servlet容器接收Web Client的请求
- Servlet容器创建一个HttpRequest对象,将WebClient请求的信息封装到这个对象中。
- Servlet容器创建一个HttpResponse对象
- Servlet容器调用HttpServlet对象的service方法,把HttpRequest对象与HttpResponse对象作为参数传给 HttpServlet 对象。
- HttpServlet调用HttpRequest对象的有关方法,获取Http请求信息。
- HttpServlet调用HttpResponse对象的有关方法,生成响应数据。
- Servlet容器把HttpServlet的响应结果传给Web Client。
Servlet工作原理:
- 首先简单解释一下Servlet接收和响应客户请求的过程,首先客户发送一个请求,Servlet是调用service()方法对请求进行响应的,通过源代码可见,service()方法中对请求的方式进行了匹配,选择调用doGet,doPost等这些方法,然后再进入对应的方法中调用逻辑层的方法,实现对客户的响应。在Servlet接口和GenericServlet中是没有doGet()、doPost()等等这些方法的,HttpServlet中定义了这些方法,但是都是返回error信息,所以,我们每次定义一个Servlet的时候,都必须实现doGet或doPost等这些方法。
- 每一个自定义的Servlet都必须实现Servlet的接口,Servlet接口中定义了五个方法,其中比较重要的三个方法涉及到Servlet的生命周期,分别是上文提到的init(),service(),destroy()方法。GenericServlet是一个通用的,不特定于任何协议的Servlet,它实现了Servlet接口。而HttpServlet继承于GenericServlet,因此HttpServlet也实现了Servlet接口。所以我们定义Servlet的时候只需要继承HttpServlet即可。
- Servlet接口和GenericServlet是不特定于任何协议的,而HttpServlet是特定于HTTP协议的类,所以HttpServlet中实现了service()方法,并将请求ServletRequest、ServletResponse 强转为HttpRequest 和 HttpResponse。
创建Servlet对象的时机:
- Servlet容器启动时:读取web.xml配置文件中的信息,构造指定的Servlet对象,创建ServletConfig对象,同时将ServletConfig对象作为参数来调用Servlet对象的init方法。
- 在Servlet容器启动后:客户首次向Servlet发出请求,Servlet容器会判断内存中是否存在指定的Servlet对象,如果没有则创建它,然后根据客户的请求创建HttpRequest、HttpResponse对象,从而调用Servlet 对象的service方法。
- Servlet Servlet容器在启动时自动创建Servlet,这是由在web.xml文件中为Servlet设置的属性决定的。从中我们也能看到同一个类型的Servlet对象在Servlet容器中以单例的形式存在。
Servlet最常用的对象
- 请求对象(ServletRequest和HttpServletRequest):Servlet从该对象中获取来自客户端的请求信息。
- 响应对象(ServletResponse和HttpServletResponse):Servlet通过该对象来生成响应结果。
- Servlet配置对象(ServletConfig):当容器初始化一个Servlet对象时,会向Servlet提供一个ServletConfig对象,Servlet通过该对象来初始化参数信息及ServletContent对象。
- Servlet上下文对象(ServletContent):Servlet通过该对象来访问容器为当前web应用提供的各种资源。
Servlet对象模型的静态结构
Servlet API主要由两个Java包组成
- ==javax.servlet==:定义了Servlet接口及相关的通用接口和类。
- ==javax.servlet.http==:主要定义了与HTTP协议相关的HttpServlet类、HttpServletRequest接口、HTTPServletResponse接口。
Servlet API的类框图
Servlet接口
javax.servlet.Servlet接口是Servlet API的核心接口,所有的Servlet类都必须实现这一接口。
Servlet接口定义的5个方法
方法名 | 作用 | 调用 |
---|---|---|
init(ServletConfig config) | 负责初始化Servlet对象。容器在创建好Servlet对象后,就会调用该方法。 | 由Servlet容器调用 |
service(ServletRequest req, ServletResponse res) | 负责响应客户的请求,为客户提供响应的服务。当容器接收到客户端要求访问特定的Servlet对象的请求时,就会调用该Servlet对象的service方法 | 由Servlet容器调用 |
destroy() | 负责释放Servlet对象占用的资源。当Servlet对象结束生命周期时,容器会调用此方法。 | 由Servlet容器调用 |
getServletConfig() | 返回一个ServletConfig对象,在该对象中包含了Servlet的初始化参数信息 | JavaWeb应用程序访问 |
getServletInfo() | 返回一个字符串,该字符串中包含了Servlet的创建者、版本和版权等信息 | JavaWeb应用程序调用 |
Servlet接口及其实现类框图
==GenericServlet抽象类==实现了Servlet接口和ServletConfig接口,但其主要身份是Servlet,此外,它还运用装饰模式,为自己附加了ServletConfig的装饰身份。在具体实现中,GenericServlet类包装了一个ServletConfig接口的实例,通过该实例来实现ServletConfig接口中的方法。
==HttpServlet抽象类==是GenericServlet的子类。HttpServlet类为Servlet接口提供了与HTTP协议相关的通用实现,也就是说,HttpServlet对象适合运行在与客户端采用HTTP协议通信的Servlet容器或者Web服务器中。在开发JavaWeb应用时,自定义的Servlet类一般都扩展HttpServlet类。
ServletRequest接口
在service(ServletRequest req, ServletResponse res)方法中有一个ServletRequest类型的参数。ServletRequest类表示来自客户端的请求。当Servlet容器接收到客户端要求访问特定Servlet请求时,容器先解析客户端的原始请求数据,把它包装成一个ServletRequest对象。当容器调用Servlet对象的service方法时,就可以吧ServletRequest对象作为参数传给service()方法。ServletRequest接口提供了一系列用于读取客户端请求数据的方法。如下:
方法 | 描述 |
---|---|
getContentLength() | 返回请求正文的长度。如果请求正文的长度未知,则返回-1。 |
getContentType() | 获得请求正文的MIME类型。如果请求正文的类型未知,则返回null。 |
getInputStream() | 返回用于读取请求正文的输入流。 |
getLocalAddr() | 返回服务器端的ip地址。 |
getLocalName() | 返回服务器端的主机名。 |
getLocalPort() | 返回服务器端的FTP端口号。 |
getParameter(String name) | 根据给定的请求参数名,返回来自客户请求中的匹配的请求参数值。 |
getProtocol() | 返回客户端与服务器端通信所用的协议名称及版本号。 |
getReader() | 返回用于读取字符串形式的请求正文的BufferedReader对象。 |
getRemoteAddr() | 返回客户端的ip地址。 |
getRemoteHost() | 返回客户端的主机名。 |
getRemotePort() | 返回客户端的FTP端口号。 |
setAttribute(String name, Object object) | 在请求范围内保存一个属性,参数name表示属性名,参数object表示属性值。 |
getAttribute(String name) | 根据name参数给定的属性名,返回请求范围内的匹配的属性值。 |
removeAttribute(String name) | 从请求范围内删除一个属性。 |
HttpServletRequest接口
是ServletRequest接口的子接口。HttpServletRequest接口提供了用于读取HTTP请求中相关信息的方法如下:
方法 | 描述 |
---|---|
getContentPath() | 返回客户端所请求访问的Web应用的url入口。 |
getCookies() | 返回Http请求中的所有Cookie。 |
getHeader(String name) | 返回HTTP请求头部的特定项。 |
getHeaderNames() | 返回一个Enumeration对象,它包含了HTTP请求头部的所有项目名。 |
getMethod() | 返回HTTP请求方式。 |
getRequestURI() | 返回HTTP请求的头部的第一行中的URI。 |
getQueryString() | 返回HTTP请求中的查询字符串,即URI中的“?”后面的内容。 |
ServletResponse接口
Servlet通过ServletResponse对象来生成响应结果。当Servlet容器接收到客户端要求访问的特定Servlet的请求时,容器会创建一个ServletResponse对象,并把它作为参数穿给Servlet的service方法。在Servlet接口中定义了一系列与生成响应结果相关的方法。如下:
方法 | 描述 |
---|---|
setCharacterEncoding(String charset) | 设置响应正文的字符编码。响应正文的默认字符编码为ISO-8859-1。 |
setContentLength(int len) | 设置响应正文的长度。 |
setContentType(String type) | 设置响应正文的MIME类型。 |
getCharacterEncoding() | 返回响应正文的字符编码。 |
getContentType() | 返回响应正文的MIME类型。 |
setBufferSize(int size) | 设置用于存放响应正文数据的缓冲区大小。 |
getBuffereSize() | 获得用于存放响应正文数据的缓冲区大小。 |
reset() | 清空缓冲区内的正文数据,并且清空响应状态代码及响应头。 |
resetBuffer() | 仅仅清空缓冲区内的正文数据,不清空响应状态代码及响应头。 |
flushBuffer() | 强制性地把缓冲区内的响应正文数据发送到客户端。 |
isCommitted() | 返回一个boolean类型的值。如果为true。表示缓冲区内的数据已经提交给客户,即数据已经发送到客户端。 |
getOutputStream() | 返回一个ServletOutputStream对象,Servlet用它来输出二进制的正文数据。 |
getWriter() | 返回一个printWriter对象,Servlet用它来输出字符串形式的正文数据。 |
为了提高输出数据的效率,ServletOutputStream和printWriter先把数据写到缓冲区内。当缓冲区的数据被提交给客户端后,ServletResponse的isCommitted()方法返回true,在一下几种情况下,缓冲区内的数据会被提交给客户,即数据被发送到客户端:
- 当缓冲区内的数据已满时,ServletOutputStream或者printWriter会自动把缓冲区内的数据自动发送给客户端,并且清空缓冲区。
- Servlet调用ServletResponse对象的flushBuffer()方法。
- Servlet调用ServletOutputStream或者printWriter对象的flush()方法或close()方法。
==为了确保ServletOutputStream或printWriter输出所有的数据都会被提交给客户,比较安全的做法是在所有数据都输出完毕后,调用ServletOutputStream或printWriter的close()方法。==
HttpServletResponse接口
是ServletResponse接口的子接口。HttpServletResponse接口提供了与HTTP协议相关的一些方法,Servlet可以通过这些方法来设置HTTP响应头或向客户端写Cookie。
方法 | 描述 |
---|---|
addHeader(String name, String value) | 向HTTP响应头中加入一项内容。 |
sendError(int sc) | 向客户端发送一个代表特定错误的HTTP响应状态代码。 |
sendError(int sc, String msg) | 向客户端发送一个代表特定错误的HTTP响应状态代码,并且发送具体的错误消息。 |
setHeader(String name, String value) | 设置HTTP响应头中的一项内容。如果在响应头中已经存在这项内容,那么原先所做的设置将被覆盖。 |
setStatus(int sc) | 设置HTTP响应的状态代码。 |
addCookie() | 向HTTP响应中加入一个Cookie。 |
ServletConfig接口
当Servlet容器初始化一个Servlet对象时,会为这个Servlet对象创建一个ServletConfig对象。在ServletConfig对象中包含了Servlet对象的初始化参数信息,此外ServletConfig对象还与当前Web应用的ServletContext对象关联。Servlet容器在调用Servlet对象的init(ServletConfig config)方法时,会把ServletConfig对象作为参数传递给Servlet对象,init(ServletConfig config)方法会使得当前Servlet对象与ServletConfig对象之间建立关联关系。ServletConfig接口中定义了以下方法:
方法 | 描述 |
---|---|
getInitParameter(String name) | 根据给定的初始化参数名,返回匹配的初始化参数值。 |
getInitParameterNames() | 返回一个Enumeration对象,里面包含了所有的初始化参数名。 |
getservletContext() | 返回一个ServletContext对象。 |
getServletNames() | 返回Servlet的名字。 |
ServletContext接口
ServletContext是Servlet与Servlet容器之间直接通信的接口。Servlet容器在启动一个Web应用时,会为它创建一个ServletContext对象。==每个Web应用都有唯一的ServletContext对象,可以把ServletContext对象形象地理解为Web应用的总管家,同一个Web应用中的所有Servlet对象都共享一个总管家,Servlet对象们可以通过这个总管家来访问容器中的各种资源。== ServletContext接口提供的方法可以分为以下几种类型:
1. 用于在Web应用范围内存取共享数据的方法。
方法 | 描述 |
---|---|
setAttribute(String name, Object object) | 把一个Java对象与一个属性名绑定,并把它存入到ServletContext中。参数name指定属性名,参数object表示共享数据。 |
getAttribute(String name) | 根据参数给定的属性名,返回一个Object类型的对象,它表示ServletContext中与属性名匹配的属性值。 |
getAttributeNames | 返回一个Enumeration对象,该对象包含了所有存放在ServletContext中的属性名。 |
removeAttribute(String name) | 根据参数指定的属性名,从ServletContext中移除匹配的属性。 |
2. 访问当前Web应用的资源。
方法 | 描述 |
---|---|
getContextPath() | 返回当前Web应用的URL入口。 |
getInitParameter(String name) | 根据给定的参数名,返回Web应用范围内匹配的初始化参数值。在web.xml文件中,直接在根元素下定义的元素表示应用范围内的初始化参数。 |
getInitParameterNames() | 返回一个Enumeration对象,它包含了web应用范围内的所有初始化参数名。 |
getServletContextName() | 返回web应用的名字,即web.xml文件中元素的值。 |
getRequestDispatcher(String path) | 返回一个用于向其他web组件转发请求的RequestDispatcher对象。 |
3. 访问Servlet容器中的其他Web应用。
方法 | 描述 |
---|---|
getContext(String uripath) | 根据给定的参数指定的URI,返回当前Servlet容器中的其他Web应用的ServletContext对象 |
4. 访问Servlet容器的相关信息。
方法 | 描述 |
---|---|
getMajorVersion() | 返回Servlet容器支持的Java Servlet API的主版本号。 |
getMinorVersion() | 返回Servlet容器支持的Java Servlet API的次版本号。 |
getServerInfo() | 返回Servlet容器的名字和版本。 |
5. 访问服务器的文件系统资源。
方法 | 描述 |
---|---|
getRealPath(String path) | 根据参数指定的虚拟路径,返回文件系统中的一个真实路径。 |
getResource(String path) | 返回一个映射到参数指定路径的URL |
getResourceAsStream(String path) | 返回一个用于读取参数指定的文件的输入流。 |
getMimeType() | 返回参数指定的文件的MIME类型。 |
6. 输出日志。
方法 | 描述 |
---|---|
log(String msg) | 向Servlet的日志文件中写日志。 |
log(String message,Throwable throwable) | 向Servlet日志文件中写错误日志,以及异常的堆栈信息。 |
学习教材:Tomcat与JavaWeb开发技术详解(第2版).孙卫琴著