• 【Java】- Servlet管理机制


    一、什么是Servlet

      简单的说,浏览器发出请求到tocat服务器,服务器就会初始化一个servlet实例(servlet采取生命托管的方式实现单例,不存在时才会创建实例),servlet示例会启动一个线程来处理该请求,并进行响应该请求,动态生成web内容

    二、什么是Tomcat服务器

      Tomcat是Apache开发的一种servlet容器,实现了对servlet和jsp等的支持,用来处理并响应浏览器发送过来的请求,实际上Tomcat是Apache 服务器的扩展,但运行时它是独立运行的,所以当你运行tomcat 时,它实际上作为一个与    Apache 独立的进程单独运行的。

    三、web.xml配置文件解析

     1 <servlet>
     2          <!-- servlet的内部名称,自定义 -->
     3         <servlet-name>login</servlet-name>
     4         <!-- servlet的类全名:包名+类名 -->
     5         <servlet-class>com.TestServlet.servlet.LoginServlet</servlet-class>
     6         <!-- 当servlet对象立即加载时 url?后携带的重要信息, 在加载servlet类是可以直接加载进去
     7              可以通过可以在init方法内使用带ServletConfig的参数读取
     8              String value = config.getInitParameter("key");//某一个key对应的value
     9              Enumeration en = config.getInitParameterNames();//获取全部的key
    10             String name = config.getServletName();//获取当前Servlet类名
    11          ServletContext application = config.getServletContext();//获取全局上下文对象
    12        -->
    13         <init-param>
    14             <param-name>name1</param-name>
    15             <param-value>value1</param-value>
    16              <param-name>name2</param-name>
    17             <param-value>value2</param-value>
    18         </init-param>
    19         <!-- servlet对象创建优先级 -->
    20         <load-on-startup>1</load-on-startup>
    21 </servlet>
    22 <!-- servlet的映射配置 -->
    23 <servlet-mapping>
    24         <!-- servlet的内部名称,和上面的自定义servlet-name对应的标签名称一致 -->
    25         <servlet-name>login</servlet-name>
    26         <!-- servlet的映射路径(访问serclet的名称) -->
    27         <url-pattern>/index</url-pattern>
    28 </servlet-mapping>
    29 <!-- 整体详情解析 以 http://localhost:8080/index-->
    30 <!-- 通过解析url得到 index 去标签 servlet-mapping中的url-pattern标签进行匹配, 
    31      若是匹配上,得到servlet-name标签中的 login定位符,在通过 login 到
    32      servlet标签下的 servlet-name 进行匹配,若是匹配上获取  servlet-class标签的 
    33      类全名 com.TestServlet.servlet.LoginServlet, 在通过反射技术创建 LoginServlet对象实例 
    34  -->

    四、servlet类的继承关系

      自己定义一个类来继承HttpServlet
     1 public class LoginServlet extends HttpServlet {
     2 
     3     @Override
     4     protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
     5         super.service(req, resp);
     6     }
     7 
     8     @Override
     9     protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    10         super.doGet(req, resp);
    11     }
    12 
    13     @Override
    14     protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    15         super.doPost(req, resp);
    16     }
    17 }
      由上面代码可以看到,我们重写了三个常用的方法,但上面除了方法名不同,其他全部相同,这是为什么呢,我们带着这个问题,来对源码进行追根溯源
      HttpServlet类继承关系
    1 // HtppServlet继承类GenericServlet类
    2 public abstract class HttpServlet extends GenericServlet {}
    3 /* GenericServlet类,实现了三个接口,分别为
    4     Servlet:    servlet接口
    5     ServletConfig: 封装servlet配置信息
    6     Serializable:  序列化接口,在反序列化时进行版本比对
    7  */
    8 public abstract class GenericServlet implements Servlet, ServletConfig, Serializable {}

      servlet类源码解析

     1 public interface Servlet {
     2     /**
     3      * servlet声明周期
     4      * 1、init()  初始化,仅第一次servlet时执行,同时会携带一个ServletConfig参数
     5      * 2、service() 用户处理请求,每次访问servlet时都会执行一次
     6      * 3、destory() 重新配置或者重新部署项目时执行,用于销毁servlet对象,销毁后的对象由gc进行回收
     7      * */
     8     void init(ServletConfig var1) throws ServletException;
     9 
    10     ServletConfig getServletConfig();
    11 
    12     void service(ServletRequest var1, ServletResponse var2) throws ServletException, IOException;
    13 
    14     String getServletInfo();
    15 
    16     void destroy();
    17 }
      ServletConfig源码解析

     1 public interface ServletConfig {
     2     // 获取当前servlet类名
     3     String getServletName();
     4     // 获取servlet全局上下文
     5     ServletContext getServletContext();
     6     // 获取web.xml文件中<init-param>标签下某一个<param-name>标签的值
     7     String getInitParameter(String var1);
     8     // 获取web.xml文件中<init-param>标签下所有的<param-name>标签的值
     9     Enumeration<String> getInitParameterNames();
    10 }
      源码解析GenricServlet类

     1 // 序列化
     2 private static final long serialVersionUID = 1L;
     3 // ServletConfig 属性
     4 private transient ServletConfig config;
     5 // 无参构造方法
     6 public GenericServlet() {
     7 }
     8 // 实现了servlet中的destroy() 方法
     9 public void destroy() {
    10 }
    11 // 重写了并实现了ServletConfig中的getInitParameter(),便于获取web.xml配置文件中的<init-param>标签下某一个<param-name>标签的值
    12 public String getInitParameter(String name) {
    13     return this.getServletConfig().getInitParameter(name);
    14 }
    15 // 重写了并实现了ServletConfig中的getInitParameter(),便于获取web.xml配置文件中的<init-param>标签下所有的<param-name>标签的值
    16 // 返回Enumeration 可以采取while循环获取所有key值
    17 // hasMoreElements 判断是否还有key
    18 // nextElement(); 获取key值
    19 public Enumeration<String> getInitParameterNames() {
    20     return this.getServletConfig().getInitParameterNames();
    21 }
    22 
    23 // 获取当前servlet对象
    24 public ServletConfig getServletConfig() {
    25     return this.config;
    26 }
    27 
    28 // 获取servlet全局上下文
    29 //
    30 public ServletContext getServletContext() {
    31     return this.getServletConfig().getServletContext();
    32 }
    33 
    34 public String getServletInfo() {
    35     return "";
    36 }
    37 
    38 // 实现了init初始化方法,将config对象赋值给自己的config属性中,从而达到在servlet第一此加载时,就拥有config对象
    39 public void init(ServletConfig config) throws ServletException {
    40     this.config = config;
    41     this.init();
    42 }
    43 
    44 // 添加了一个Init无参方法,可以提供用户进行重写
    45 public void init() throws ServletException {
    46 }
    47 
    48 // 增加了自己的log方法,控制台打印日志
    49 public void log(String msg) {
    50     this.getServletContext().log(this.getServletName() + ": " + msg);
    51 }
    52 
    53 public void log(String message, Throwable t) {
    54     this.getServletContext().log(this.getServletName() + ": " + message, t);
    55 }
    56 
    57 // 该类由用户自己定以 所以没有实现接口方法
    58 public abstract void service(ServletRequest var1, ServletResponse var2) throws ServletException, IOException;
    59 
    60 // 获取serlet类对象名
    61 public String getServletName() {
    62     return this.config.getServletName();
    63 }
      源码解析HttpServlet类
     1 // doGet方法,未进行任何处理,
     2 protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
     3     String protocol = req.getProtocol();
     4     String msg = lStrings.getString("http.method_get_not_supported");
     5     if (protocol.endsWith("1.1")) {
     6         resp.sendError(405, msg);
     7     } else {
     8         resp.sendError(400, msg);
     9     }
    10 
    11 }
    12 
    13 // doPost方法,未进行任何处理,
    14 protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    15     String protocol = req.getProtocol();
    16     String msg = lStrings.getString("http.method_post_not_supported");
    17     if (protocol.endsWith("1.1")) {
    18         resp.sendError(405, msg);
    19     } else {
    20         resp.sendError(400, msg);
    21     }
    22 
    23 }
    24 
    25 // 提供了自己的受保护的service方法,便于子类访问,类中未进行具体操作,而是通过获取请求类型来定位调用方法来处理
    26 protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    27     String method = req.getMethod();
    28     long lastModified;
    29     if (method.equals("GET")) {
    30         lastModified = this.getLastModified(req);
    31         if (lastModified == -1L) {
    32             this.doGet(req, resp);
    33         } else {
    34             long ifModifiedSince;
    35             try {
    36                 ifModifiedSince = req.getDateHeader("If-Modified-Since");
    37             } catch (IllegalArgumentException var9) {
    38                 ifModifiedSince = -1L;
    39             }
    40 
    41             if (ifModifiedSince < lastModified / 1000L * 1000L) {
    42                 this.maybeSetLastModified(resp, lastModified);
    43                 this.doGet(req, resp);
    44             } else {
    45                 resp.setStatus(304);
    46             }
    47         }
    48     } else if (method.equals("HEAD")) {
    49         lastModified = this.getLastModified(req);
    50         this.maybeSetLastModified(resp, lastModified);
    51         this.doHead(req, resp);
    52     } else if (method.equals("POST")) {
    53         this.doPost(req, resp);
    54     } else if (method.equals("PUT")) {
    55         this.doPut(req, resp);
    56     } else if (method.equals("DELETE")) {
    57         this.doDelete(req, resp);
    58     } else if (method.equals("OPTIONS")) {
    59         this.doOptions(req, resp);
    60     } else if (method.equals("TRACE")) {
    61         this.doTrace(req, resp);
    62     } else {
    63         String errMsg = lStrings.getString("http.method_not_implemented");
    64         Object[] errArgs = new Object[]{method};
    65         errMsg = MessageFormat.format(errMsg, errArgs);
    66         resp.sendError(501, errMsg);
    67     }
    68 
    69 }
    70 
    71 // 实现了接口servlet类中的service()方法,但没有将具体处理,仅仅将ServletRequest和ServletResponse进行
    72 // 此处体现了面向对象思想,也体现了适配器模式的应用。
    73 public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException {
    74     HttpServletRequest request;
    75     HttpServletResponse response;
    76     try {
    77         request = (HttpServletRequest)req;
    78         response = (HttpServletResponse)res;
    79     } catch (ClassCastException var6) {
    80         throw new ServletException("non-HTTP request or response");
    81     }
    82 
    83     // 调用该类的受保护类
    84     this.service(request, response);
    85 }
      servlet生命周期
        servlet对象是单实例管理,底层采用生命周期托管方式实现
        Servlet对象是延迟加载的机制,在第一次访问时创建对象,且只加载一次
        Servlet对象的创建 使用 销毁的三个方法分别是:
        init() 第一次访问servlet时执行
        service() 每一次访问servlet都会调用一次
        destroy() 重新配置或者部署项目时,调用该方法进行销毁servlet对象,销毁的对象由GC垃圾回收机制进行回收
      Servlet管理机制总结
        1、我们自己的类继承了HttpServlet
        2、HttpServlet继承了GenericServlet
        3、GenericServlet实现了三个接口
          Servlet接口 ServletConfig接口 Serializable接口
          ServletConfig接口拥有四个方法,但都是抽象方法
            String = getInitParamName(String v) // 初始化servlet类
            Enumeration<String> = getInitParamNames() // 获取所有key
            String = getServetName // 获取类对象名称
            ServletContext = getServletContext() // 获取类对象上下文
          Servlet接口提供了五个方法,全部都是抽象
            void init(ServletConfig sc); // 初始化servlet类
            void service(ServletRequest req, ServletResponse res) throw ServletException, IOException
            void destroy() //servlet对象销毁方法
          ServletConfig getServletConfig() // 获取servlet类对象
            String getServletInfo() // 获取servlet类信息 若版本,作者,版权等
          Serializable接口 没有提供任何方法
        4、GenericServlet
          将9个抽象方法实现了8个,还有一个service()没有实现,此处体现了缺省适配器模式
          自己添加了 init() 无参数方法 和 log() 方法
        5、HttpServlet 类,体现了面向对象的思想,跟HTTP有关
          该类中实现了service(),但仅对方法中的形参ServletRequset和ServletResponse进行了强制转换成HttpServletRequset和HttpServletResponse
          同时添加了一个protect修饰的service方法,即最终方法,但是该方法即通过 request.getMethod()来获取请求类型,并进行方法调用
          添加一些属于自己的且和请求方式对应的具体方法,如
            doGet(HttpServletRequset req, HttpServletResponse res) throw ServletException, IOException
            doGet(HttpServletRequset req, HttpServletResponse res) throw ServletException, IOException
          添加了一些属于自己的属性
          get post put等
        6、 我们自己的servlet类继承HttpServlet,重写service方法,或者doGet/doPost等方法
          若是我们自己类没有重写service方法,那么会从父类GenericServlet中的service去查找doGet/doPost等方法,抛出405

    五、Tomcat请求响应流程图

  • 相关阅读:
    Smarty简单配置代码
    5.27权限练习
    PHP函数中的变量
    PHP文件格式数组
    PHP文件操作
    MongoCola MongoDB 客户端管理工具
    使用NPOI库导入导出EXCEL
    MVC Filter使用
    MVC设计及使用拓展
    C# 基础·语法篇
  • 原文地址:https://www.cnblogs.com/tar8087/p/14456647.html
Copyright © 2020-2023  润新知