javaWEB总结(10):HttpServlet成长史

来源:互联网 发布:广数980g71编程实例 编辑:程序博客网 时间:2024/05/14 10:12

前言:

从Servlet,ServletConfig到GenericServlet再到Httpservlet的整个过程,相当于Httpservlet的成长史,我们不需要写那么臃肿的代码,开发难度由复杂到简单,本文主要介绍这几者的关系。


1.关系图

(1)GenericServlet实现了Servlet接口,ServletConfig接口,和序列化接口。表明该对象可以被序列化和反序列化(注:本文不对序列化介绍,如对序列化感兴趣,请参考文章:http://www.jianshu.com/p/31dc46bb42dd)。

(2)HttpServlet继承了GenericServlet。



2.过程(1)

GenericServlet实现Servlet接口,ServletConfig接口,此过程最巧妙的方法有两个。

(a): 声明私有变量,保存初始化init(ServletConfig config)方法时的ServletConfig对象,并且写了getServletConfig方法。这样子类在调用GenericServlet的getServletConfg().getXXX()方法就可以获得ServletConfig的所有方法,原来只有在init方法中才可以获取。


(b): 初始化init(ServletConfig config)的方法中调用了无参的init()方法。这样避免了继承了GenericServlet的子类重写init(ServletConfig config)方法,而无法调用this.config=config,造成私有变量为空,当使用getServletConfg().getXXX()方法时会报错的问题。



Servlet源码:

    package javax.servlet;     import java.io.IOException;            public interface Servlet {                     //负责初始化Servlet对象。容器一旦创建好Servlet对象后,就调用此方法来初始化Servlet对象           public void init(ServletConfig config) throws ServletException;                           //方法负责响应客户的请求,提供服务。当容器接收到客户端要求访问特定的servlet请求时,就会调用Servlet的service方法            public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException;                         /*         Destroy()方法负责释放Servlet 对象占用的资源,当servlet对象结束生命周期时,servlet容器调用此方法来销毁servlet对象.       **/          public void destroy();                           /*         说明:Init(),service(),destroy() 这三个方法是Servlet生命周期中的最重要的三个方法。         **/                                /*         返回一个字符串,在该字符串中包含servlet的创建者,版本和版权等信息         **/          public String getServletInfo();                      /*        GetServletConfig: 返回一个ServletConfig对象,该对象中包含了Servlet初始化参数信息         **/              public ServletConfig getServletConfig();        }  

ServletConfig源码


 public interface ServletConfig {                  //获取指定初始化名的初始化值        public String getServletName();            //获取所有初始化参数名组成的 Enumeration对象        public ServletContext getServletContext();              //获取 ServletContext对象          public String getInitParameter(String name);          //获取servlet配置名称        public Enumeration getInitParameterNames();                  }  

GenericServlet源码


    package javax.servlet;            import java.io.IOException;      import java.util.Enumeration;            //抽象类GenericServlet实现了Servlet接口的同时,也实现了ServletConfig接口和Serializable这两个接口       public abstract class GenericServlet           implements Servlet, ServletConfig, java.io.Serializable      {          //私有变量,保存 init()传入的ServletConfig对象的引用          private transient ServletConfig config;                    //无参的构造方法          public GenericServlet() { }                          /*         ------------------------------------         以下方法实现了servlet接口中的5个方法         实现Servlet接口方法开始         ------------------------------------         */                                  /*         实现接口Servlet中的带参数的init(ServletConfig Config)方法,将传递的ServletConfig对象的引用保存到私有成员变量中,         使得GenericServlet对象和一个ServletConfig对象关联.         同时它也调用了自身的不带参数的init()方法         **/                    public void init(ServletConfig config) throws ServletException {            this.config = config;            this.init();   //调用了无参的 init()方法          }                //无参的init()方法          public void init() throws ServletException {                }                              //空实现了destroy方法          public void destroy() { }                                       //实现了接口中的getServletConfig方法,返回ServletConfig对象          public ServletConfig getServletConfig()           {             return config;          }                    //该方法实现接口<Servlet>中的ServletInfo,默认返回空字符串          public String getServletInfo() {             return "";          }                              //唯一没有实现的抽象方法service(),仅仅在此声明。交由子类去实现具体的应用          //在后来的HttpServlet抽象类中,针对当前基于Http协议的Web开发,HttpServlet抽象类具体实现了这个方法         //若有其他的协议,直接继承本类后实现相关协议即可,具有很强的扩展性                      public abstract void service(ServletRequest req, ServletResponse res)       throws ServletException, IOException;                    /*         ------------------------------------         实现Servlet接口方法结束         ------------------------------------         */                                                                          /*       ---------------------------------------------        *以下四个方法实现了接口ServletConfig中的方法        实现ServletConfig接口开始       ---------------------------------------------        */               //该方法实现了接口<ServletConfig>中的getServletContext方法,用于返回servleConfig对象中所包含的servletContext方法          public ServletContext getServletContext() {             return getServletConfig().getServletContext();          }                    //获取初始化参数          public String getInitParameter(String name) {           return getServletConfig().getInitParameter(name);          }                    //实现了接口<ServletConfig>中的方法,用于返回在web.xml文件中为servlet所配置的全部的初始化参数的值          public Enumeration getInitParameterNames() {             return getServletConfig().getInitParameterNames();                  //获取在web.xml文件中注册的当前的这个servlet名称。没有在web.xml 中注册的servlet,该方法直接放回该servlet的类名。         //法实现了接口<ServleConfig>中的getServletName方法            public String getServletName() {              return config.getServletName();          }                   /*       ---------------------------------------------        实现ServletConfig接口结束       ---------------------------------------------      */                               public void log(String msg) {             getServletContext().log(getServletName() + ": "+ msg);          }                              public void log(String message, Throwable t) {             getServletContext().log(getServletName() + ": " + message, t);          }      }  


3.过程(2)

HttpServlet继承GenericServlet,此过程最巧妙的方法也有两个。


(a):在原service(ServletRequest req,ServletResponse res)方法中将ServletRequest和ServletResponse 强转为HttpServletRequest和HttpServletResponse,再调用重载的service(HttpServletRequest req,HttpServletResponse resp)方法,这样我们便可以调用与HTTP请求更多的方法。


(b):用HttpServletRequest的getMethod()方法,获取请求方式,并调用相应的doXXX方法,这样我们就可以直接根据请求方式而写入相应的doXXX方法中,最常见的就是doGet和doPost。


HttpServlet源码

    package javax.servlet.http;      .....  //节约篇幅,省略导入包            public abstract class HttpServlet extends GenericServlet          implements java.io.Serializable       {                private static final String METHOD_GET = "GET";          private static final String METHOD_POST = "POST";          ......                             /**          * Does nothing, because this is an abstract class.          * 抽象类HttpServlet有一个构造函数,但是空的,什么都没有          */          public HttpServlet() { }                                    /*分别执行doGet,doPost,doOpitions,doHead,doPut,doTrace方法         在请求响应服务方法service()中,根据请求类型,分贝调用这些doXXXX方法         所以自己写的Servlet只需要根据请求类型覆盖响应的doXXX方法即可。         */                    //doXXXX方法开始          protected void doGet(HttpServletRequest req, HttpServletResponse resp)              throws ServletException, IOException          {              String protocol = req.getProtocol();              String msg = lStrings.getString("http.method_get_not_supported");              if (protocol.endsWith("1.1")) {                  resp.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED, msg);              } else {                  resp.sendError(HttpServletResponse.SC_BAD_REQUEST, msg);              }          }                          protected void doHead(HttpServletRequest req, HttpServletResponse resp)              throws ServletException, IOException          {              .......          }            protected void doPost(HttpServletRequest req, HttpServletResponse resp)              throws ServletException, IOException          {              String protocol = req.getProtocol();              String msg = lStrings.getString("http.method_post_not_supported");              if (protocol.endsWith("1.1")) {                  resp.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED, msg);              } else {                  resp.sendError(HttpServletResponse.SC_BAD_REQUEST, msg);              }          }             protected void doPut(HttpServletRequest req, HttpServletResponse resp)              throws ServletException, IOException  {              //todo          }                                     protected void doOptions(HttpServletRequest req, HttpServletResponse resp)              throws ServletException, IOException {             //todo          }                        protected void doTrace(HttpServletRequest req, HttpServletResponse resp)               throws ServletException, IOException   {                   //todo          }                    protected void doDelete(HttpServletRequest req,                                  HttpServletResponse resp)              throws ServletException, IOException   {              //todo          }             //doXXXX方法结束                                    //重载的service(args0,args1)方法          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);              }          }                            //实现父类的service(ServletRequest req,ServletResponse res)方法         //通过参数的向下转型,然后调用重载的service(HttpservletRequest,HttpServletResponse)方法                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);  //调用重载的service()方法          }                   ......//其他方法      }  

以上就是HttpServlet的成长史,在实际应用的时候,直接继承HttpServlet找到相应的doXXX方法即可,的确使代码简洁很多。

2 0