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接口提供的方法可分为以下几种类型。

  1. 用于在Web应用范围内存取共享数据的方法
方法作用
setAttribute(String name, java.lang.Object object)把一个 Java对象与一个属性名绑定,并把它存入到ServletContext中。参数name指定属性名,参数object表示共享数据
getAttribue(String name)根据参数给定的属性名,返回一个Object类型的对象,它表示ServletContext中与属性名匹配的属性值
getAttributeNames()返回一个Enumeration对象,该对象包含了所有存放在ServletContext中的属性名
removeAttribute(String name)根据参数指定的属性名,从ServletContext中删除匹配的属性
  1. 访问当前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对象
  1. 访问Servlet容器中的其他Web应用
方法作用
getCongtext(String uripatch)根据参数指定的URI,返回当前Servlet容器中其他Web应用的ServletContext对象
  1. 访问Servlet容器相关信息
方法作用
getMajorVersion()返回Servlet 容器支持的Java Servlet API的主版本号
getMinorVersion()返回Servlet容器支持的Java Servlet API的次版本号
getServerInfo()返回Servlet容器的名字和版本。
  1. 访问服务器端的文件系统资源
方法作用
getRealPath(String path)根据参数指定的虚拟路径,返回文件系统中的一个真实的路径。
getResource(String path)返回一个映射到参数指定的路径的URL。
getResourceAsStream(String path)返回一个用于读取参数指定的文件的输入流。
getMimeType(String file)返回参数指定的文件的MIME类型。
  1. 输出日志
方法作用
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应用所占用的相关资源。


Logo

CSDN联合极客时间,共同打造面向开发者的精品内容学习社区,助力成长!

更多推荐