• 简述Servlet的生命周期


    前言

            在讲述Servlet的生命周期之前,我们一定要了解什么是Servlet?

            Servlet(Server Applet)是Java Servlet的简称,称为小服务程序或服务连接器,用Java编写的服务器端程序,具有独立于平台和协议的特性,主要功能在于交互式地浏览和生成数据,生成动态Web内容。

            在Web开发阶段,我们如果要编写一个完善的服务器,就要关注许多繁琐的格式化的基础语句,一个简单的html页面就可能需要上千行底层代码:

    1. //基于TCP协议连接+HTTP协议通信的服务器端
    2. public class HttpServer01 {
    3. public static void main(String[] args) {
    4. try (ServerSocket serverSocket = new ServerSocket(8080)) {
    5. while(true) {
    6. //客户端基于HTTP协议发起请求
    7. Socket socket= serverSocket.accept();
    8. System.out.println("有新的客户端连接");
    9. //读取到客户端的请求头内容(基于HTTP协议格式)
    10. try(BufferedReader reader=new BufferedReader(new InputStreamReader(socket.getInputStream()));
    11. BufferedWriter writer=new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()))) {
    12. String line=null;
    13. while((line=reader.readLine())!=null) {
    14. //读到空行,代表请求头结束
    15. //由于是GET请求,不存在request body(请求体)
    16. //所以退出请求头的读取
    17. if (line.length()==0) {
    18. break;
    19. }
    20. System.out.println(line);
    21. }
    22. System.out.println("开始响应...");
    23. String response="优惠券:"+UUID.randomUUID().toString()+"";
    24. // response header 响应头
    25. writer.write("HTTP/1.1 200 ok\r\n");
    26. writer.write("Connection:close\r\n");
    27. writer.write("Content-Type:text/html\r\n");
    28. ...
    29. writer.newLine();
    30. writer.newLine();
    31. writer.write(response);
    32. }
    33. }
    34. } catch (IOException e) {
    35. e.printStackTrace();
    36. }
    37. }
    38. }

            以上代码是一个简单的在浏览器上显示一段UUID优惠码 ,可以看到在响应时,响应头输出内容十分繁琐。

     控制台输出结果:

            因此,在JavaEE平台上,处理TCP连接,解析HTTP协议这些繁琐的底层工作统统被扔给现成的Web服务器去做,我们只需要把自己的应用程序运行在Web服务器上即可。

            为了实现这一目的,JavaEE提供了Servlet API,我们使用Servlet API编写自己的Servlet来处理HTTP请求,Web服务器实现Servlet API接口,来实现底层功能。

            简单来讲,一个Web App就是由一个或多个Servlet组成的,每个Servlet通过注解说明自己能处理的路径:

    1. @WebServlet("/hello.do")//所有的请求路径必须以"/"开头
    2. public class HelloServlet extends HttpServlet{
    3. ...
    4. }

             接下来就要根据请求方式来重新父类方法:

     

    Servlet的生命周期

            在通过一个URL路径发起对一个Servlet请求的过程中,其本质是在调用执行Servlet实例的doXXX()方法。

    1. import java.io.IOException;
    2. import javax.servlet.ServletException;
    3. import javax.servlet.annotation.WebServlet;
    4. import javax.servlet.http.HttpServlet;
    5. import javax.servlet.http.HttpServletRequest;
    6. import javax.servlet.http.HttpServletResponse;
    7. @WebServlet("/home.do")
    8. public class Homeservlet extends HttpServlet{
    9. //1.实例化
    10. //调用构造方法、创建Homeservlet实例
    11. public Homeservlet() {
    12. System.out.println("1.Homeservlet实例被创建");
    13. }
    14. //2.初始化
    15. //重写HttpServlet父类的init()方法
    16. //通过实例自动调用init()方法
    17. @Override
    18. public void init() throws ServletException {
    19. System.out.println("2.Homeservlet实例初始化");
    20. }
    21. //3.服务
    22. //通过实例调用父类(HttpServlet)的service()方法
    23. //service()方法会根据请求的方法调用子类重写的doGet()或doPost()方法
    24. //如果子类没有重写相应的方法,则调用父类的该方法,响应405
    25. //根据请求方式的不同,调用不同的请求方法
    26. @Override
    27. protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    28. System.out.println("被GET请求了");
    29. }
    30. //4.销毁
    31. //调用destroy()方法
    32. @Override
    33. public void destroy() {
    34. System.out.println("Homeservlet实例被销毁");
    35. }
    36. //生命周期1实例化、2初始化、3服务、4销毁
    37. }

             我们运行以上代码,并且请求/home.do路径,最后停止服务器。运行结果为:

    通过以home.do为例,总结到:

             Servlet的生命周期:指Servlet实例创建和使用的过程。

            一个生命周期包括:实例化、初始化、服务、销毁。

    1. 实例化:根据Servlet请求的路径,查找该Servlet的实例。如果实例不存在,则通过调用构造方法,完成Servlet实例的创建。
    2. 初始化:通过该Servlet的实例调用init()方法,执行初始化的逻辑。
    3. 服务:通过该Servlet的实例调用service()方法,如果子类没有重写该方法,则调用HttpServlet父类的service()方法,在父类的该方法中进行请求方式的判断,并调用响应的doXXX()方法:
      1. protected void service(HttpServletRequest req, HttpServletResponse resp)
      2. throws ServletException, IOException {
      3. String method = req.getMethod();
      4. if (method.equals(METHOD_GET)) {
      5. long lastModified = getLastModified(req);
      6. if (lastModified == -1) {
      7. // servlet doesn't support if-modified-since, no reason
      8. // to go through further expensive logic
      9. doGet(req, resp);
      10. } else {
      11. long ifModifiedSince;
      12. try {
      13. ifModifiedSince = req.getDateHeader(HEADER_IFMODSINCE);
      14. } catch (IllegalArgumentException iae) {
      15. // Invalid date header - proceed as if none was set
      16. ifModifiedSince = -1;
      17. }
      18. if (ifModifiedSince < (lastModified / 1000 * 1000)) {
      19. // If the servlet mod time is later, call doGet()
      20. // Round down to the nearest second for a proper compare
      21. // A ifModifiedSince of -1 will always be less
      22. maybeSetLastModified(resp, lastModified);
      23. doGet(req, resp);
      24. } else {
      25. resp.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
      26. }
      27. }
      28. } else if (method.equals(METHOD_HEAD)) {
      29. long lastModified = getLastModified(req);
      30. maybeSetLastModified(resp, lastModified);
      31. doHead(req, resp);
      32. } else if (method.equals(METHOD_POST)) {
      33. doPost(req, resp);
      34. } else if (method.equals(METHOD_PUT)) {
      35. doPut(req, resp);
      36. } else if (method.equals(METHOD_DELETE)) {
      37. doDelete(req, resp);
      38. } else if (method.equals(METHOD_OPTIONS)) {
      39. doOptions(req,resp);
      40. } else if (method.equals(METHOD_TRACE)) {
      41. doTrace(req,resp);
      42. } else {
      43. //
      44. // Note that this means NO servlet supports whatever
      45. // method was requested, anywhere on this server.
      46. //
      47. String errMsg = lStrings.getString("http.method_not_implemented");
      48. Object[] errArgs = new Object[1];
      49. errArgs[0] = method;
      50. errMsg = MessageFormat.format(errMsg, errArgs);
      51. resp.sendError(HttpServletResponse.SC_NOT_IMPLEMENTED, errMsg);
      52. }
      53. }

      如果子类重写doXXX()方法,则调用子类重写后的doXXX()方法;如果子类没有重写doXXX()方法,则调用父类的doXXX()方法,在父类的方法实现中,返回一个405状态码的错误页面。

      405状态码:代表请求的方式服务器不提供支持。 

    4. 销毁:服务器关闭或重启时,会销毁所有的Servlet实例,会调用Servlet实例的destroy()方法。

     

     

  • 相关阅读:
    Android四大组件详解
    PaddleX场景实战:PP-TS在电压预测场景上的应用
    Linux UWB Stack实现——MCPS通道访问
    Pytorch之卷积层实战
    php:下拉列表查询(静态数据+数据库数据)
    双十一客服培训话术
    传统关系型数据库(mysql),缓存(redis),elasticsearch
    【C++难点收录】“为什么C++难,你真的理解了这些吗?”《常见面试题》
    机器学习笔记之变分推断(五)重参数化技巧
    关于回文判断(c语言版)
  • 原文地址:https://blog.csdn.net/w259149/article/details/126451557