1、service()方法源码解析
先来看HttpServlet的service()方法:
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { //获取http request的method参数,其实就是html的form标签 //中method属性对应的字符串 String method = req.getMethod(); long errMsg; //判断请求方式 if(method.equals("GET")) { //获取最后被修改时间 errMsg = this.getLastModified(req); if(errMsg == -1L) { /**如果servlet不支持http request header的if-modified-since属性 * 则继续处理 **/ this.doGet(req, resp); } else { //如果支持这个属性 long ifModifiedSince; try { ifModifiedSince = req.getDateHeader("If-Modified-Since"); } catch (IllegalArgumentException var9) { ifModifiedSince = -1L; } /** * 如果客户端的文件最后修改时间和服务器端的文件最后修改时间一致则返回304不需要修改状态 * 这样服务器就不返回html,浏览器读取本地缓存文件,否则重新获取服务器端的对应html文件 **/ if(ifModifiedSince < errMsg / 1000L * 1000L) { this.maybeSetLastModified(resp, errMsg); this.doGet(req, resp); } else { resp.setStatus(304); } } } else if(method.equals("HEAD")) { errMsg = this.getLastModified(req); this.maybeSetLastModified(resp, errMsg); this.doHead(req, resp); } else if(method.equals("POST")) { this.doPost(req, resp); } else if(method.equals("PUT")) { this.doPut(req, resp); } else if(method.equals("DELETE")) { this.doDelete(req, resp); } else if(method.equals("OPTIONS")) { this.doOptions(req, resp); } else if(method.equals("TRACE")) { this.doTrace(req, resp); } else { //如果请求不是以上的所有请求方式,该方法就会响应501错误,也就是不支持这种请求 String errMsg1 = lStrings.getString("http.method_not_implemented"); Object[] errArgs = new Object[]{method}; errMsg1 = MessageFormat.format(errMsg1, errArgs); resp.sendError(501, errMsg1); } } public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException { HttpServletRequest request; HttpServletResponse response; try { request = (HttpServletRequest)req; response = (HttpServletResponse)res; } catch (ClassCastException var6) { throw new ServletException("non-HTTP request or response"); } this.service(request, response); }
很显然HttpServlet这个类里面有两个service()方法。首先要知道的是用户自定义的Servlet都是HttpServlet的子类,也就是要继承HttpServlet,而HttpServlet是从GenericServlet继承而来,GenericServlet类要实现javax.servlet.Servlet接口。而GenericServlet类提供的除service()方法以外所有接口方法都默认实现。所以service()是一个抽象方法,GenericServlet的派生类必须对该方法重置才能实现期望的业务逻辑。
先说以上HttpServlet的第二种service()方法,该方法是来自父类GenericServlet,
HttpServlet将其重置。该方法收到客服端请求后,创建request对象和response对象,并强制转化为HttpServletRequest和HttpServletResponse类型的对象,在处理请求期间发生错误,会主动抛出异常。最后调用HttpServlet自身的service()方法,也就是第一种service()方法
然后我们来看第一种service()方法,客服端发送请求至服务器端,服务器将请求发送到Servlet,首先会调用init()方法初始化Servlet,然后Servlet的执行时期会调用service()方法,该方法会自动判断来自客服端的请求方式,根据不同请求方式调用不同方法,如果是get请求,则调用doGet()方法,如果是post请求,则调用doPost()方法。我们可以看到里面的请求方式有HEAD、GET、POST、DELETE、OPTIONS、TRACE
根据不同的请求会调用不同方法,当我们使用这些方法时根据不同的需求重写方法实现业务逻辑。如果请求不是以上的所有请求方式,该方法就会响应501错误,也就是不支持这种请求。处理完请求后自然要返回响应,最后调用destory()方法销毁Servlet。
2、doGet()和doPost()方法源码解析
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { //获取协议 String protocol = req.getProtocol(); //获取http.method_get_not_supported的国际化字符串 String msg = lStrings.getString("http.method_get_not_supported"); if(protocol.endsWith("1.1")) { //如果是HTTP/1.1,返回405禁止访问方法错误 resp.sendError(405, msg); } else { //如果不是HTTP/1.1,返回400错误的请求错误 resp.sendError(400, msg); } } 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(405, msg); } else { resp.sendError(400, msg); } }
两个方法如果不被重写,那执行时默认会调用HttpServlet的代码,首先获取协议,然后获取国际化字符串,最后判断协议,如果协议为HTTP/1.1,返回405禁止访问方法错误,//如果不是HTTP/1.1,返回400错误的请求错误。