javaweb-Servlet基础
Servlet1.1 Servlet简介Servlert就是sun公司开发动态web的一门技术Sun公司在这些在这些API中提供一个接口叫做:Servlet,如果你想开发一个Servlet程序,只需要完成两个小步骤:编写一个类,实现Servlet接口把开发好的java类部署到web服务器中把实现了Servlet接口的java程序叫做:Servlet6.2 HelloServlet(Sun公司的)S
1,Servlet简介
- Servlert就是sun公司开发动态web的一门技术
- Sun公司在这些在API中提供一个接口叫做:Servlet,如果你想开发一个Servlet程序,只需要完成两个小步骤:
- 编写一个类,实现Servlet接口
- 把开发好的java类部署到web服务器中
把实现了Servlet接口的java程序叫做:Servlet
2,Servlet结构
Servlet接口有两个默认的实现类:HttpServlet,GenericServlet
HttpServlet,GenericServlet及Servlet之间的关系:
2.1 Servlet结构:由源代码进行展开说明
Servlet接口源代码:Servlet接口定义了5个方法
public interface Servlet {
void init(ServletConfig var1) throws ServletException;
ServletConfig getServletConfig();
void service(ServletRequest var1, ServletResponse var2) throws ServletException, IOException;
String getServletInfo();
void destroy();
}
抽象类GenericServlet源代码:抽象类GenericServlet将service()方法定义成抽象方法
public abstract class GenericServlet implements Servlet, ServletConfig, Serializable {
......
public abstract void service(ServletRequest var1, ServletResponse var2) throws ServletException, IOException;
......
}
类HttpServlet源代码:
public abstract class HttpServlet extends GenericServlet {
......
protected void service(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException
{
String method = req.getMethod();
if (method.equals(METHOD_GET)) {
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) {
// 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)) {
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 {
//
// Note that this means NO servlet supports whatever
// method was requested, anywhere on this server.
//
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,GenericServlet,HttpServlet三者的关系,HttpServlet类实现了Servlet接口中的service(ServletRequest req, ServletResponse res)方法,该方法实际上调用的是它的重载方法:
service(HttpServletRequest req, HttpServletResponse resp)
在以上重载方法service()方法中,首先调用HttpServletRequest类型的req参数的getMethod()方法,从而获得客户端的请求方式,然后依据该请求方式来调用匹配的服务方法。如果是GET方式,则调用doGet()方法;如果为POST()方式,则调用doPost()方法,以此类推。
HttpServlet类为所有针对特定请求方式的 doXXX()方法提供了默认的实现。在HttpServlet类的默认实现中,doGet(),doPost(),doPut(),doDelete()方法都会向客户端返回一个错误:
- 如果客户与服务器之间采用HTTP 1.1 协议通信,那么返回的错误为HttpServletResponse.SC_METHOD_NOT_ALLOWED(对应HTTP协议中响应状态代码为405的错误)。
- 如果客户与服务器之间不是采用 HTTP 1.1 协议通信,那么返回的错误为HttpServletResponse.SC_BAD_REQUEST(对应HTTP协议中响应状态代码为400的错误)。
源代码如下:
public abstract class HttpServlet extends GenericServlet {
......
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException
{
String protocol = req.getProtocol();
String msg = lStrings.getString("http.method_get_not_supported");
if (protocol.endsWith("1.1")) {
resp.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED, msg);
} else {
resp.sendError(HttpServletResponse.SC_BAD_REQUEST, msg);
}
}
protected void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException
{
String protocol = req.getProtocol();
String msg = lStrings.getString("http.method_post_not_supported");
if (protocol.endsWith("1.1")) {
resp.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED, msg);
} else {
resp.sendError(HttpServletResponse.SC_BAD_REQUEST, msg);
}
}
//其余两个方法也是如此,就没有贴出
......
}
对于HttpServlet 类的具体子类(指我们自己写的类),一般会针对客户端的特定请求方式,来覆盖HttpServlet父类中的相应doXXX()方法。为了使doXXX()方法能被Servlet容器访问,应该把访问权限设为public。
2.2 ServletRequest接口
在Servlet 接口的service(ServletRequest req, ServletResponse res)方法中有一个ServletRequest类型的参数。ServletRequest 类表示来自客户端的请求。当Servlet 容器接收到客户端要求访问特定Servlet的请求时,容器先解析客户端的原始请求数据,把它包装成一个ServletRequest 对象。当容器调用Servlet 对象的service()方法时,就可以把ServletRequest对象作为参数传给service0方法。
ServletRequest接口提供了一系列用于读取客户端的请求数据的方法。
方法 | 作用 |
---|---|
getContentLengt() | 返回请求正文的长度。如果请求正文的长度未知,则返回-1。 |
getContentType() | 获得请求正文的MIME类型。如果请求正文的类型未知,则返回null。 |
getInputStream() | 返回用于读取请求正文的输入流。 |
getLocalAddr() | 返回服务器端的IP地址。 |
getLocalName() | 返回服务器端的主机名。 |
getLocalPort() | 返回服务器端的FTP端口号。 |
getParameter(String name) | 根据给定的请求参数名,返回来自客户请求中的匹配的请求参数值。 |
getProtocol() | 返回客户端与服务器端通信所用的协议的名称及版本号。 |
getReader() | 返回用于读取字符串形式的请求正文的BufferedReader对象。 |
getRemoteAddr() | 返回客户端的IP地址。 |
getRemoteHost() | 返回客户端的主机名。 |
getRemotePort() | 返回客户端的FTP端口号。 |
setAttribute(String name,java.lang.Object object) | 在请求范围内保存一个属性,参数name表示属性名,参数object表示属性值 |
getAttribute(string name) | 根据name参数给定的属性名,返回请求范围内得匹配的属性值 |
removeAttribute(String name) | 从请求范围内删除一个属性 |
2.3 HttpServletRequest接口
HttpServletRequest接口是ServletRequest接口的子接口。HttpServlet类的重载service()方法及doGet()和doPost()等方法都有一个HttpServletRequest类型的参数:
protected void service(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException
方法 | 作用 |
---|---|
getContextPath() | 返回客户端所请求访问的Web应用的URL入口。例如,如果客户端访问的URL为http://localhost:8080/helloapp/info, 那么该方法返回"/helloapp" |
getCookies() | 返回HTTP请求中的所有Cookie |
getHeader(String name) | 返回HTTP请求头部的特定项 |
getHeaderNames() | 返回一个Enumeration 对象,它包含了HTTP请求头部的所有项目名 |
getMethod() | 返回HTTP请求方式 |
getRequestURI() | 返回HTTP请求的头部的第1行中的URI(不是URL) |
getQueryString() | 返回HTTP请求中的查询字符串,即URL中的“?”后面的内容。例如,如果客户端访问的URL为http://localhost:8080/helloapp/info?username= Tom,那么该方法返回“username=Tom’’ |
@WebServlet(urlPatterns="/RequestServlet")
public class RequestServlet extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
Enumeration<String> headerNames = req.getHeaderNames();
while(headerNames.hasMoreElements()){
String nextElement = headerNames.nextElement();
String header = req.getHeader(nextElement);
System.out.println(nextElement + " : " + header);
}
System.out.println("**********");
System.out.println(req.getScheme());
System.out.println(req.getServerName());
System.out.println(req.getServerPort());
System.out.println(req.getContextPath());
System.out.println(req.getRequestURI());
System.out.println(req.getRequestURL());
System.out.println(req.getMethod());
System.out.println(req.getQueryString());
}
}
当请求路径为这样时:http://localhost:8080/servlet/RequestServlet?name=Tom
host : localhost:8080
connection : keep-alive
sec-ch-ua : "Google Chrome";v="87", " Not;A Brand";v="99", "Chromium";v="87"
sec-ch-ua-mobile : ?0
upgrade-insecure-requests : 1
user-agent : Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.141 Safari/537.36
accept : text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
sec-fetch-site : none
sec-fetch-mode : navigate
sec-fetch-user : ?1
sec-fetch-dest : document
accept-encoding : gzip, deflate, br
accept-language : zh-CN,zh;q=0.9
cookie : JSESSIONID=67F043E039991BBE6A5A7D6D7680291A; Idea-f1857c54=eb1b5459-b5b0-466a-9159-718e6a1c8565; Webstorm-9975f15e=ac3734a4-25fd-4b84-a5c0-ce22e24578ea; Hm_lvt_aa5c701f4f646931bf78b6f40b234ef5=1609941449,1609997771
**********
http
localhost
8080
8080
/servlet
/servlet/RequestServlet
http://localhost:8080/servlet/RequestServlet
GET
name=Tom
2.2 ServletResponse接口
在Servlet 接口的service(ServletRequest req, ServletResponse res)方法中有一个ServletResponse类型的参数。Servlet 通过ServletResponse 对象来生成响应结果。当Servlet容器接收到客户端要求访问特定Servlet 的请求时,容器会创建一个ServletResponse对象,并把它作为参数传给Servlet的service()方法。
在ServletResponse接口中定义了一系列与生成响应结果相关的方法。
方法 | 作用 |
---|---|
setCharacterEncoding(String charset) | 设置响应正文的字符编码。响应正文的默认字符编码为ISO-8859-1 |
setContentLength(int len) | 设置响应正文的长度 |
setContentType(String type) | 设置响应正文的MIME类型。 |
getCharacterEncoding() | 返回响应正文的字符编码 |
getContentType() | 返回响应正文的MIME类型 |
setBufferSize(int size) | 设置用于存放响应正文数据的缓冲区的大小 |
getBufferSize() | 获得用于存放响应正文数据的缓冲区的大小 |
reset() | 清空缓冲区内的正文数据,并且清空响应状态代码及响应头 |
resetBuffer() | 仅仅清空缓冲区内的正文数据,不清空响应状态代码及响应头 |
flushBuffer() | 强制性地把缓冲区内的响应正文数据发送到客户端 |
isCommitted() | 返回一个boolean类型的值。如果为true,表示缓冲区内的数据已经提交给客户,即数据已经发送到客户端 |
getOutputStream() | 返回一个ServletOutputStream对象,Servlet 用它来输出二进制的正文数据 |
getWriter() | 返回一个 PrintWriter对象,Servlet 用它来输出字符串形式的正文数据 |
ServletResponse中响应正文的默认MIME类型为text/plain,即纯文本类型。而HTTPServletResponse中响应正文的默认MIME类型为text/html,即HTML文档类型。
2.3 HttpServletResponse接口
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(Cookie cookie) | 向HTTP响应中加入一个Cookie. |
2.4 ServletContext接口
ServletContext是Servlet与Servlet 容器之间直接通信的接口。Servlet 容器在启动一个 Web应用时,会为它创建一个ServletContext对象。每个Web 应用都有唯一的ServletContext对象,可以把ServletContext对象形象地理解为Web应用的总管家,同一个 Web应用中的所有Servlet 对象都共享一个总管家, Servlet对象们可通过这个总管家来访问容器中的各种资源。
ServletContext接口提供的方法可分为以下几种类型。
- 用于在Web应用范围内存取共享数据的方法
方法 | 作用 |
---|---|
setAttribute(String name, java.lang.Object object) | 把一个 Java对象与一个属性名绑定,并把它存入到ServletContext中。参数name指定属性名,参数object表示共享数据 |
getAttribue(String name) | 根据参数给定的属性名,返回一个Object类型的对象,它表示ServletContext中与属性名匹配的属性值 |
getAttributeNames() | 返回一个Enumeration对象,该对象包含了所有存放在ServletContext中的属性名 |
removeAttribute(String name) | 根据参数指定的属性名,从ServletContext中删除匹配的属性 |
- 访问当前Web应用的资源
方法 | 作用 |
---|---|
getContextPath() | 返回当前Web应用的URL入口。 |
getInitParameter(String name) | 根据给定的参数名,返回Web应用范围内的匹配的初始化参数值。在web.xml 文件中,直接在< web-app >根元素下定义的< context-param >元素表示应用范围内的初始化参数 |
getInitParameterNames() | 返回一个Enumeration对象,它包含了Web应用范围内的所有初始化参数名 |
getServletContextName() | 返回Web 应用的名字,即web.xml 文件中< display-name>元素的值 |
getRequestDispatcher(String path) | 返回一个用于向其他Web组件转发请求的RequestDispatcher对象 |
- 访问Servlet容器中的其他Web应用
方法 | 作用 |
---|---|
getCongtext(String uripatch) | 根据参数指定的URI,返回当前Servlet容器中其他Web应用的ServletContext对象 |
- 访问Servlet容器相关信息
方法 | 作用 |
---|---|
getMajorVersion() | 返回Servlet 容器支持的Java Servlet API的主版本号 |
getMinorVersion() | 返回Servlet容器支持的Java Servlet API的次版本号 |
getServerInfo() | 返回Servlet容器的名字和版本。 |
- 访问服务器端的文件系统资源
方法 | 作用 |
---|---|
getRealPath(String path) | 根据参数指定的虚拟路径,返回文件系统中的一个真实的路径。 |
getResource(String path) | 返回一个映射到参数指定的路径的URL。 |
getResourceAsStream(String path) | 返回一个用于读取参数指定的文件的输入流。 |
getMimeType(String file) | 返回参数指定的文件的MIME类型。 |
- 输出日志
方法 | 作用 |
---|---|
log(String msg) | 向Servlet的日志文件中的写日志 |
log(String message,java.lang.Throwable throwable) | 向Servlet的日志文件中写错误日志,以及异常的堆栈信息 |
2.5 案例
案例内容为:将配置文件中的内容取出,保存到ServletContext中,之后将其取出输出到页面上
1,构建一个普通的Maven项目,删除src目录,以后在这个空的目录中建立module,并将此空的Maven项目作为主工程,把依赖尽可能的放在主工程的pom.xml文件中
2,添加依赖:
<dependencies>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>4.0.1</version>
</dependency>
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>jsp-api</artifactId>
<version>2.2</version>
</dependency>
</dependencies>
过滤资源:
<build>
<resources>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.properties</include>
<include>**/*.xml</include>
</includes>
</resource>
<resource>
<directory>src/main/resources</directory>
<includes>
<include>**/*.properties</include>
<include>**/*.xml</include>
</includes>
</resource>
</resources>
</build>
3,在主工程中创建一个web项目
4,关于Maven父子工程的理解:
父项目中会有
<modules>
<module>servlet-01</module>
</modules>
子项目中会有
<parent>
<artifactId>javaweb-servlet-1</artifactId>
<groupId>com.mofei</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
父项目中的java子目录可以直接使用
son extends father
5,Maven环境优化
(1)修改web.xml为最新的
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0"
metadata-complete="true">
</web-app>
(2)将maven的结构搭建完整(添加java,resource目录)
6,创建类继承HttpServlet
java/com/mofei/servlet/HelloServlet.java
public class HelloServlet extends HttpServlet {
//由于get或者post只是请求实现的不同的方式,可以相互调用,业务逻辑都一样;
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setContentType("text/html");
resp.setCharacterEncoding("UTF-8");
ServletContext servletContext = this.getServletContext();
InputStream is = servletContext.getResourceAsStream("/WEB-INF/classes/db.properties");
Properties prop = new Properties();
prop.load(is);
String status = prop.getProperty("status");
String username = prop.getProperty("username");
String password = prop.getProperty("password");
servletContext.setAttribute("username",username);
servletContext.setAttribute("password", password);
resp.getWriter().println("存储status : " + status);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
java/com/mofei/servlet/GetHelloServlet.java
public class GetHelloServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setContentType("text/html");
resp.setCharacterEncoding("UTF-8");
ServletContext servletContext = this.getServletContext();
String username = (String) servletContext.getAttribute("username");
String password = (String) servletContext.getAttribute("password");
resp.getWriter().println("username : " + username + ";" + "password : " + password);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
配置文件db.properties内容为:
username=root
password=123456
status=success
7,在web.xml注册Servlet以及为Servlet映射一个URL
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0"
metadata-complete="true">
<!--注册一个Servlet
name : 定义Servlet的名字
class : 指定Servlet的完整类名(包括包名)
<servlet-mapping>元素用于为Servlet映射一个URL
-->
<servlet>
<servlet-name>hello</servlet-name>
<servlet-class>com.mofei.servlet.HelloServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>hello</servlet-name>
<url-pattern>/hello</url-pattern>
</servlet-mapping>
<servlet>
<servlet-name>getHello</servlet-name>
<servlet-class>com.mofei.servlet.GetHelloServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>getHello</servlet-name>
<url-pattern>/getH</url-pattern>
</servlet-mapping>
</web-app>
8,配置Tomcat
9,启动Tomcat进行测试:
首先访问:http://localhost:8080/sv2/hello
其次访问:http://localhost:8080/sv2/getH
重启服务器之后,如果先访问:http://localhost:8080/sv2/getH
3,Servlet原理
3.1 Servlet?Servlet容器?
Servlet是基于Java技术的web组件,容器托管的,用于生成动态内容。像其他基于Java的组件技术一样,Servlet也是基于平台无关的Java类格式,被编译为平台无关的字节码,可以被基于Java技术的web server动态加载并运行。容器,有时候也叫做servlet引擎,是web server为支持servlet功能扩展的部分。客户端通过Servlet容器实现的请求/应答模型与Servlet交互。
service 方法由 Servlet 容器调用,以允许 Servlet 响应一个请求。Servlet 容器传递 javax.servlet.ServletRequest 对象和 javax.servlet.ServletResponse 对象。ServletRequest 对象包含客户端 HTTP 请求信息,ServletResponse 则封装servlet 响应。通过这两个对象,您可以写一些需要 servlet怎样服务和客户怎样请求的代码。
Servlet容器有时候也叫做Servlet引擎,是Web服务器或应用程序服务器的一部分,用于在发送的请求和响应之上提供网络服务,解码基于MIME的请求,格式化基于MIME的响应。Servlet不能独立运行,它必须被部署到Servlet容器中,由容器来实例化和调用Servlet的方法,Servlet容器在Servlet的生命周期内包容和管理Servlet。
3.2 原理图
3.3 解惑---->名词:web容器 Tomcat容器 Servlet容器
三个名词之间的等价于包含关系是什么形式的?
web容器是一种服务程序,在服务器一个端口就有一个提供相应服务的程序,而这个程序就是处理从客户端发出的请求,如JAVA中的Tomcat容器,ASP的IIS或PWS都是这样的容器。一个服务器可以有多个容器。
Tomcat 是一个小型的轻量级应用服务器,普遍用于中小型系统和并发访问量较低的场合,是开发和调试JSP 程序的首选。对于一个初学者来说,可以这样认为,当在一台机器上配置好Apache 服务器,可利用它响应对HTML 页面的访问请求。实际上Tomcat 部分是Apache 服务器的扩展,但它是独立运行的,所以当你运行tomcat 时,它实际上作为一个与Apache 独立的进程单独运行的。
这里的诀窍是,当配置正确时,Apache 为HTML页面服务,而Tomcat 实际上运行JSP 页面和Servlet。另外,Tomcat和IIS、Apache等Web服务器一样,具有处理HTML页面的功能,另外它还是一个Servlet和JSP容器,独立的Servlet容器是Tomcat的默认模式。不过,Tomcat处理静态HTML的能力不如Apache服务器。
4 Servlet的生命周期
JavaWeb应用的生命周期由Servlet 容器来控制,而Servlet作为JavaWeb应用的最核心的组件,其生命周期也由Servlet容器来控制。Servlet的生命周期可以分为3个阶段:初始化阶段、运行时阶段和销毁阶段。在jax.erevet.Servlet接口中定义了3个方法: init()、 service()和destroy(),它们将分别在Servlet的不同阶段被Servlet容器调用。
public interface Servlet {
void init(ServletConfig var1) throws ServletException;
ServletConfig getServletConfig();
void service(ServletRequest var1, ServletResponse var2) throws ServletException, IOException;
String getServletInfo();
void destroy();
}
- Servlet对象的创建时机
Servlet对象是由Tomcat来创建
Servlet在被第一次访问的时候由TOMCAT来初始化创建,而且只创建一次,创建成功后,Servlet对象直接存在于TOMCAT的运行内存中。其他的请求如果再访问则不再创建,直接调用完成请求处理。但是如果,在web.xml中配置了load-on-startup,则该Servlet在服务器启动的时候就会被初始化创建。
Servlet在服务期间只会被创建一次,而TOMCAT服务器每接收一个请求就会创建一个线程来调用Servlet对象中的service方法来处理请求,所以Servlet对象是被多线程共享的一个对象。在Servlet不要轻易的声明普通属性来记录数据,会造成数据混乱。
init方法,Servlet被创建的时候触发执行 - Servlet对象的销毁时机
在Tomcat服务器关闭的时候
destory方法,在Servlet对象被销毁的时候调用
public class LifeServlet extends HttpServlet {
public LifeServlet() {
System.out.println("lifeServlet");
}
@Override
public void init() throws ServletException {
System.out.println("init");
}
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("service");
}
@Override
public void destroy() {
System.out.println("destroy");
}
}
执行此Servlet打印的结果如下:
4.1 初始化阶段(init方法)
Servlet的初始化阶段包括4个步骤:
(1) Servlet 容器加载Servlet类,把它的 .class 文件中的数据读入到内存中。
(2) Servlet 容器创建ServletConfig对象。ServletConfig 对象包含了特定Servlet的初始化配置信息,如Servlet的初始参数。此外,Servlet 容器还会使得ServletConfig对象与当前Web应用的ServletContext对象关联。
(3) Servlet 容器创建Servlet 对象。
(4) Servlet 容器调用Servlet 对象的init(ServletConfig config)方法。在Servlet接口的GenericServlet实现类的init(ServletConfig config)方法中,会建立Servlet对象与ServletConfig 对象的关联关系。
以上初始化步骤创建了Servlet 对象和ServletConfig 对象,并且Servlet 对象与ServletConfig对象关联,而ServletConfig 对象又与当前Web应用的ServletContext 对象关联。当Servlet 容器初始化完Servlet 后,Servlet 对象只要通过getServletContext()方法就能得到当前Web应用的ServletContext对象。
在下列情况之一,Servlet 会进入初始化阶段。
(1)当前Web应用处于运行时阶段,特定Servlet被客户端首次请求访问。多数Servlet都会在这种情况下被Servlet容器初始化。
(2)如果在web.xml文件中为一个 Servlet 设置了< load-on-startup >元素,那么当Servlet容器启动Servlet所属的Web应用时,就会初始化这个Servlet。以下代码配置了3个Servlet: Servlet1、 Servlet2 和ServletX.
<servlet>
<servlet-name>servlet1</servlet-name>
<servlet-class>servlet1</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet>
<servlet-name>servlet2</servlet-name>
<servlet-class>servlet2</servlet-class>
<load-on-startup>2</load-on-startup>
</servlet>
<servlet>
<servlet-name>servletX</servlet-name>
<servlet-class>servletX</servlet-class>
</servlet>
其中 Servlet1和 Servlet2的< load-on-startup >的值分别为1和2,因此当Servlet容器启动当前Web应用时, Servlet1被第一个初始化,Servlet2被第二个初始化。而ServletX没有配置 < load-on-startup >元素,因此当Servlet容器启动当前Web应用时,ServletX不会被初始化,只有当客户端首次请求访问ServletX时,它才会被初始化。
(3)当Web应用被重新启动时,Web应用中的所有Servlet都会在特定的时刻被重新初始化。
4.2 运行时阶段
这是Servlet的生命周期中的最重要阶段。在这个阶段, Servlet 可以随时响应客户端的请求。当Servlet容器接收到要求访问特定Servlet的客户请求时,Servlet容器会创建针对于这个请求的ServletRequest 对象和ServletResponse对象,然后调用相应Servlet对象的service()方法。 service()方法从ServletRequest 对象中获得客户请求信息并处理该请求,再通过ServletResponse对象生成响应结果。
当Servlet 容器把Servlet 生成的响应结果发送给了客户,Servlet 容器就会销毁ServletRequest对象和ServletResponse对象。
4.2 销毁阶段
当Web应用被终止时,Servlet 容器会先调用Web应用中所有Servlet 对象的destroy()方法,然后再销毁这些Servlet对象。在destroy()方法的实现中,可以释放Servlet所占用的资源( 例如关闭文件输入流和输出流,关闭与数据库的连接等)。此外,容器还会销毁与Servlet对象关联的ServletConfig对象。
Servlet生命周期总结
默认是从第一次被访问到Tomcat服务器关闭,如果配置了load-on-startup则是从服务器开启到服务器关闭。
Servlet的生命周期是由容器管理的,分别经历五个阶段。
类加载
new :实例化
init():初始化
service():执行服务
destroy():回收销毁
当客户端浏览器第一次请求Servlet时,容器会实例化这个Servlet,然后调用一次init方法,并在新的线程中执行service方法处理请求。service方法执行完毕后容器不会销毁这个Servlet而是做缓存处理,当客户端浏览器再次请求这个Servlet时,容器会从缓存中直接找到这个Servlet对象,并再一次在新的线程中执行Service方法。当容器在销毁Servlet之前对调用一次destory方法。
多次请求servlet并查看控制台输出即可印证上述结论,值得注意的是,如果需要Servlet在服务启动时就实例化并初始化,我们可以在servlet的配置中添加load-on-startup 配置启动顺序,配置的数字为启动顺序,避免冲突
5,JavaWeb应用的生命周期
JavaWeb应用的生命周期是由Servlet 容器来控制的。归纳起来,JavaWeb 应用的生命周期包括3个阶段。
- 启动阶段:加载Web应用的有关数据,创建ServletContext 对象,对Filter (过滤器)和一些Servlet进行初始化。
- 运行时阶段:为客户端提供服务。
- 终止阶段:释放Web应用所占用的各种资源。
4.1 启动阶段
Servlet容器在启动JavaWeb应用时,会完成以下操作:
(1)把web.xml文件中的数据加载到内存中。
(2)为JavaWeb应用创建一个 ServletContext 对象。
(3)对所有的Filter 进行初始化。
(4)对那些需要在Web应用启动时就被初始化的Servlet进行初始化。
4.2 运行时阶段
这是JavaWeb应用最主要的生命阶段。在这个阶段,它的所有Servlet 都处于待命状态,随时可以响应客户端的特定请求,提供相应的服务。假如客户端请求的Servlet还不存在,Servlet 容器会先初始化Servlet, 然后再调用它的service()服务方法。
4.3 终止阶段
Servlet容器在终止JavaWeb应用时,会完成以下操作:
(1)销毁JavaWeb应用中所有处于运行时状态的Servlet。
(2)销毁JavaWeb应用中所有处于运行时状态的Filter.
(3)销毁所有与JavaWeb应用相关的对象,如ServletContext对象等,并且释放Web应用所占用的相关资源。
更多推荐
所有评论(0)