zoukankan      html  css  js  c++  java
  • 【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请求响应流程图

  • 相关阅读:
    ASP.NET编程的十大技巧
    C#学习心得(转)
    POJ 1177 Picture (线段树)
    POJ 3067 Japan (树状数组)
    POJ 2828 Buy Tickets (线段树)
    POJ 1195 Mobile phones (二维树状数组)
    HDU 4235 Flowers (线段树)
    POJ 2886 Who Gets the Most Candies? (线段树)
    POJ 2418 Cows (树状数组)
    HDU 4339 Query (线段树)
  • 原文地址:https://www.cnblogs.com/tar8087/p/14456647.html
Copyright © 2011-2022 走看看