在之前的文章Servlet执行原理浅谈中对Servlet的整个原理做了大概介绍。我们知道客户端发送的请求是交给Servlet中的service方法进行处理。而在实际使用时,并没有直接重写service方法,而是继承了HttpServlet,重写了doGet、doPost等方法,而这期间又发生了什么呢。
首先,我们观察Servlet这个接口:
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 
 | public interface Servlet {void init(ServletConfig var1) throws ServletException;
 
 ServletConfig getServletConfig();
 
 void service(ServletRequest var1, ServletResponse var2) throws ServletException, IOException;
 
 String getServletInfo();
 
 void destroy();
 }
 
 | 
Servlet是一个接口,其中包含5个方法,我们大多真正使用的是service方法,其他的几个方法并不常用。因此,就出现了以下两个实现类:

首先我们看GenericServlet类:
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 
 | public abstract class GenericServlet implements Servlet, ServletConfig, Serializable {private static final long serialVersionUID = 1L;
 private transient ServletConfig config;
 
 public void destroy() {
 }
 
 public ServletConfig getServletConfig() {
 return this.config;
 }
 
 public String getServletInfo() {
 return "";
 }
 
 public void init(ServletConfig config) throws ServletException {
 this.config = config;
 this.init();
 }
 
 public void init() throws ServletException {
 }
 
 public abstract void service(ServletRequest var1, ServletResponse var2) throws ServletException, IOException;
 
 
 }
 
 | 
为方便展示,这里只罗列出了其实现的父类方法,自身的方法未列出。
从其源码中可以看出,除了service方法(改写成抽象方法),其他四个方法都具体实现了(有的只有return,也是实现)。因此,当我们使用继承GenericServlet类时,只需要具体实现service方法即可。从上面的类图上看出,Servlet容器帮我们设计好了继承类——HttpServlet。
我们继续看HttpServlet:
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 
 | public abstract class HttpServlet extends GenericServlet {
 protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
 String msg = lStrings.getString("http.method_get_not_supported");
 this.sendMethodNotAllowed(req, resp, msg);
 }
 
 
 protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
 String msg = lStrings.getString("http.method_post_not_supported");
 this.sendMethodNotAllowed(req, resp, msg);
 }
 
 protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
 String method = req.getMethod();
 long lastModified;
 if (method.equals("GET")) {
 lastModified = this.getLastModified(req);
 if (lastModified == -1L) {
 this.doGet(req, resp);
 } else {
 long ifModifiedSince;
 try {
 ifModifiedSince = req.getDateHeader("If-Modified-Since");
 } catch (IllegalArgumentException var9) {
 ifModifiedSince = -1L;
 }
 
 if (ifModifiedSince < lastModified / 1000L * 1000L) {
 this.maybeSetLastModified(resp, lastModified);
 this.doGet(req, resp);
 } else {
 resp.setStatus(304);
 }
 }
 } else if (method.equals("HEAD")) {
 lastModified = this.getLastModified(req);
 this.maybeSetLastModified(resp, lastModified);
 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 {
 String errMsg = lStrings.getString("http.method_not_implemented");
 Object[] errArgs = new Object[]{method};
 errMsg = MessageFormat.format(errMsg, errArgs);
 resp.sendError(501, errMsg);
 }
 
 }
 
 
 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(lStrings.getString("http.non_http"));
 }
 
 this.service(request, response);
 }
 
 }
 
 | 
为了方便展示,我们只保留了doGet、doPost以及service方法。
从HttpServlet中的源码可以看出,它不仅实现了service方法,还增加了重载形式。在之前的原理讲解中,我们知道客户端发送的请求首先交给Servlet中的service方法进行处理。
在这里,首先发送的请求来到第一个service方法:
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 
 | 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(lStrings.getString("http.non_http"));
 }
 
 this.service(request, response);
 }
 
 | 
里面的参数req就包含着我们的请求信息(请求头、请求体、请求参数…)。在其方法体中,首先将请求(req)与响应(res)进行转型 –> Http。最后,调用了其重载方法this.service(request, response);
具体再看该段重载方法:
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 
 | protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {String method = req.getMethod();
 long lastModified;
 if (method.equals("GET")) {
 lastModified = this.getLastModified(req);
 if (lastModified == -1L) {
 this.doGet(req, resp);
 } else {
 long ifModifiedSince;
 try {
 ifModifiedSince = req.getDateHeader("If-Modified-Since");
 } catch (IllegalArgumentException var9) {
 ifModifiedSince = -1L;
 }
 
 if (ifModifiedSince < lastModified / 1000L * 1000L) {
 this.maybeSetLastModified(resp, lastModified);
 this.doGet(req, resp);
 } else {
 resp.setStatus(304);
 }
 }
 } else if (method.equals("HEAD")) {
 lastModified = this.getLastModified(req);
 this.maybeSetLastModified(resp, lastModified);
 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 {
 String errMsg = lStrings.getString("http.method_not_implemented");
 Object[] errArgs = new Object[]{method};
 errMsg = MessageFormat.format(errMsg, errArgs);
 resp.sendError(501, errMsg);
 }
 }
 
 | 
它对获得的请求req进行方法的请求判断,如果是method=GET,就调用doGet方法;如果method=POST,就调用doPost方法,如果method等于其他5种类型之一,就调用其相应的方法。
这里我们继续看doGet、doPost方法:
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 
 | protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {String msg = lStrings.getString("http.method_get_not_supported");
 this.sendMethodNotAllowed(req, resp, msg);
 }
 
 
 protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
 String msg = lStrings.getString("http.method_post_not_supported");
 this.sendMethodNotAllowed(req, resp, msg);
 }
 
 | 
这是不是我们在实际应用中,经常重写的两个方法。我们对请求的处理和响应的设置是不是都在这里面。所以归根结底,我们的请求还是交给了service方法进行处理,是在service中又继而调用更加具体的方法(doGet、doPost…)来为我们处理请求。
现在对整个Servlet处理请求做个流程图总结:
