javaWEB总结(10):HttpServlet成长史

本文解析了从Servlet到Httpservlet的演化过程,包括各组件之间的关系及其实现机制。介绍了GenericServlet如何实现Servlet和ServletConfig接口,以及Httpservlet如何继承GenericServlet并针对HTTP协议进行优化。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

前言:

从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方法即可,的确使代码简洁很多。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值