• 详细理解servlet实现的三种方式和生命周期


     

    现在很多的开发都是用的框架,然后很多同学学习的时候又是直接接触的框架,对于底层的一些开发,完全没有任何的了解。虽然对于业务上面来说,没有什么问题。但是很多时候当你被面试问到,或者是想要了解框架底层原理的时候,这就不得不知道了。所以今天详细说说它。

    开发servlet的三种方式

    1、实现servlet接口(偏向底层)

    2、继承GenericServlet(觉得1不好用,就开发了这个,现在基本没啥用)

    3、继承HttpServlet(现在大多数用这个)

    理解实现servlet接口的方式,理解servlet生命周期

    首先当servlet第一次被调用的时候,会调用servlet的init方法,把servlet实例装载到内存中。

    之后会调用service方法,当第二次servlet被访问的时候就会直接调用service函数。

    只有当web应用关闭,或者容器关闭,或者电脑关闭时候,才会调用destroy方法销毁servlet

    下面是浏览器发出请求后servlet执行的流程图

    Servlet接口有五个方法

    init初始化,就是把servlet装载到内存中,只会被调用一次

    getServletConfig获取servletConfig对象

    service主要的服务方法,放业务逻辑,每次都会被调用

    getServletInfo得到servlet配置信息

    destroy销毁该servlet,从内存中清除掉

    继承GenericServlet

    GenericServlet实现了servlet接口

    然后只有一个抽象方法需要你自己去重写

    那就是service方法,所以相比来说init别的方法他都帮你实现好了,只要你写service方法就可以了。

    至少看起来继承GenericServlet比直接实现servlet接口要方便

    这个类是在javax.servlet.GenericServlet下的

    继承HttpServlet

    因为后来发现servlet主要是为了服务于http请求的,而且发现GenericServlet对于http来说还不够好

    所以有了HttpServlet,首先它是继承自GenericServlet

    然后它有很多http相关的方法,post,get,put等待

    用户可以根据自己需要来实现这些方法

    每个过来的请求都会调用service方法,最后service会根据不用的请求分发到不同的地方去做。

    下面的问题中会在源码中详细说明。

    下面有关servlet service描述错误的是?

    1、不管是post还是get方法提交过来的连接,都会在service中处理

    每次请求都会调用service方法,最终都会在service中处理,正确;


    2、doGet/doPost 则是在 javax.servlet.GenericServlet 中实现的

    GenericServlet只是继承了Servlet的接口,实现了它其中的5个方法,其中需要用户重写的是service方法,而doGet/doPost是因为之后出现了HttpServlet才有的,是针对http请求才有了这个类,才有了doPost和doGet,所以是错误的。


    3、service()是在javax.servlet.Servlet接口中定义的

    Servlet接口一共定义了5个方法,其中就有service(),正确;


    4、service判断请求类型,决定是调用doGet还是doPost方法

    下面详细说说最后一个选项。

    我们来看一看源码

    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 / 1000 * 1000)) {
                // 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);
        }
        }
     

    这个就是HttpServlet中service方法的源码

    首先我们看到的就是String method = req.getMethod();

    这个就是通过request获取方法

    然后根据方法判断调用哪一个方法

    要说明的是前面它已经定义好了那些字符串

    private static final String METHOD_DELETE = "DELETE"; 
       private static final String METHOD_HEAD = "HEAD"; 
       private static final String METHOD_GET = "GET"; 
       private static final String METHOD_OPTIONS = "OPTIONS"; 
       private static final String METHOD_POST = "POST"; 
       private static final String METHOD_PUT = "PUT"; 
       private static final String METHOD_TRACE = "TRACE"; 
    所以第四个选项说:service判断请求类型,决定是调用doGet还是doPost方法,是正确的。

    需要指出的是

    前面说过

    HttpServlet是继承自GenericServlet,而GenericServlet需要用户实现一个service,刚才我们看到的是它自己的

    而在HttpServlet中其实是有的。它肯定要写这样一个方法的。

    public void service(ServletRequest req, ServletResponse res)
        throws ServletException, IOException
        {
        HttpServletRequest    request;
        HttpServletResponse    response;
        
        try {
            request = (HttpServletRequest) req;
            response = (HttpServletResponse) res;
        } catch (ClassCastException e) {
            throw new ServletException("non-HTTP request or response");
        }
        service(request, response);
        }
     

    源码是这样的,它会把原来的ServletRequest 请求直接强转换成HttpServletRequest然后再去调用它正真的service方法。

    这点是需要指出的,HttpServletRequest比ServletRequest进行了进一步的封装,方法更适合http。

    Servlet的生命周期分为5个阶段:加载、创建、初始化、处理客户请求、卸载。
    (1)加载:容器通过类加载器使用servlet类对应的文件加载servlet
    (2)创建:通过调用servlet构造函数创建一个servlet对象
    (3)初始化:调用init方法初始化
    (4)处理客户请求:每当有一个客户请求,容器会创建一个线程来处理客户请求
    (5)卸载:调用destroy方法让servlet自己释放其占用的资源
     
  • 相关阅读:
    抽象工厂设计模式【看了挺多的,还是这个最清楚】
    js1:对象的学习,构造函数,继承构造函数【使用教材:JavaScript深度剖析第2版】
    如何用DW设计界面 结合 VS设计后台代码
    初识微服务架构
    Mysql分库分表方案
    真实经历,互联网大厂升职加薪那些事
    fastjson数据格式转换 SerializerFeature属性详解
    基于Spring Boot和Spring Cloud实现微服务架构学习
    MySQL中tinytext、text、mediumtext和longtext详解
    下载知乎视频
  • 原文地址:https://www.cnblogs.com/zedosu/p/6709809.html
Copyright © 2020-2023  润新知