zoukankan      html  css  js  c++  java
  • servlet-servlet的简单认识——源码解析

     

    Servlet的基本认识

    本内容主要来源于《看透Spring MVC源码分析与实践——韩路彪》一书

    Servlet是server+Applet的缩写,表示一个服务器的应用。Servlet其实就是一套规范。

    一、servlet接口

      Servlet3.1中servlet接口定义如下:

    public interface Servlet {
    
       //init方法在容器启动时被容器调用(当load-on-startup设置为负数或者不设置时会在Servlet第一次用到时才被调用),只会调用一次。
       public void init(ServletConfig config) throws ServletException;
    
       //getServletConfig方法用于获取ServletConfig。
       public ServletConfig geServletConfig();
    
        //service方法用于处理一个请求。
       public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException;
    
       //getServletInfo方法可以获取一些Servlet相关的信息,这个方法需要自己去实现,默认返回空字符串。
       public String getServletInfo();
    
       //destroy方法用于在Servlet销毁(一般指关闭服务器)时释放一些资源,也只会调用一次。
       public void destroy();
    }

       1.1init方法:

        init方法被调用时会接受到一个ServletConfig(Servlet的配置)类型的参数,是容器传进去的。我们在web.xml中定义Servlet时通过init-param标签配置的参数就是通过ServletConfig来保存的。

      1.2 getServletConfig 方法:

      1.3 service方法:

      1.4 getServletInfo方法:

      1.5 destroy方法:

    二、ServletConfig接口:

      ServletConfig接口的定义如下:

    public interface ServletConfig {
    
        //获取Servlet的名字,也就是在web.xml中定义的servlet-name
        public String getServletName();
    
        //返回的ServletContext代表着我们这个应用本身。其实就是Tomcat中Context的门面类ApplicationContextFacade。
        public ServletContext getServletContext();
    
        //用于获取init-param配置的参数
        public String getInitParameter(String name);
    
        //用于获取配置的所有init-param的名字的集合
        public Enumeration<String> getInitParameterNames();
    }

       其中方法getServletContext返回值ServletContext代表了应用本身,所以ServletContext里边设置的参数就可以被当前应用的所有的Servlet所共享。

      我们做项目的时候都知道参数可以保存在session中,也可以保存在application中,而servlet的参数就是保存在servletContext中。

      可以这么理解,ServletConfig是Servlet级的,ServletContext是Context级的。当然ServletContext的功能非常强大,不只是保存配置参数。

      在ServletContext的接口中有一个方法:public Servlet getContext(String uripath),它可以根据路径获取到同一个站点下的别的应用的ServletContext,由于安全的原因,一般返回的是null。

    三、GenericServlet抽象类:

    public abstract class GenericServlet implements Servlet, ServletConfig,
            java.io.Serializable {
    }

      GenericServlet是Servlet的默认实现,主要做了三件事:

        1.实现了ServletConfig的接口。

          我们可以直接调用ServletConfig里面的方法。因此当我们需要获取ServletContext时就可以直接调用getServletConfig(),而不用调用getServletConfig().getServletContext()了。

        2.提供了无参的init方法。

          GenreicServlet实现了Servlet的init(ServletConfig config)方法,将里面的config赋值给了自身的内部变量config,然后调用了无参的init方法,这个无参的init()方法是个模板方法,可以在子类中通过覆盖它来完成自己的初始化工作。

        @Override
        public void init(ServletConfig config) throws ServletException {
            this.config = config;
            this.init();
        }
        public void init() throws ServletException {
            // NOOP by default
        }

        3.提供了两个log方法。

          一个是记录日志,一个是记录异常。

    //记录日志   
     public void log(String msg) {
            getServletContext().log(getServletName() + ": " + msg);
        }
    //记录异常
        public void log(String message, Throwable t) {
            getServletContext().log(getServletName() + ": " + message, t);
        }

      一般我们都是有自己的日志处理方式,所以用的不多。而且GenreicServlet是与具体协议无关的。

     

    四、HttpServlet抽象类:

      HttpServlet使用HTTP协议实现的Servlet的基类,因此在我们写Servlet的时候直接继承HttpServlet就可以了。Spring MVC中的DispatcherServlet就是继承的HttpServlet。

      因为是和协议相关的,所以这里就比较关心请求的事情了。在HttpServlet中主要重写了service方法,将父类中(Servlet接口)service方法的参数ServletRequest和ServletResponse转换为HttpServletRequest和HttpServletResponse。

    //重写父类的方法    
    @Override
        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");
            }
            //调用本类中http的处理方法
            service(request, response);
        }
    
    //本类中方法
      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;
                    try {
                        ifModifiedSince = req.getDateHeader(HEADER_IFMODSINCE);
                    } catch (IllegalArgumentException iae) {
                        // Invalid date header - proceed as if none was set
                        ifModifiedSince = -1;
                    }
                    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);
            }
        }

       这里只是将Servlet中的一些源码做些分析。

  • 相关阅读:
    理解和应用队列机制
    Visual Studio for Mac第四预
    宇宙第一开发工具
    Visual Studio 2017
    Vue开源
    Redux 和 ngrx 创建更佳的 Angular 2
    Redis缓存用起来
    C#6
    spring声明式事务 同一类内方法调用事务失效
    Spring事务管理--多个ORM框架在使用时的情况分析
  • 原文地址:https://www.cnblogs.com/whx20100101/p/10088333.html
Copyright © 2011-2022 走看看