在之前的文章Servlet执行原理浅谈中对Servlet
的整个原理做了大概介绍。我们知道客户端发送的请求是交给Servlet
中的service
方法进行处理。而在实际使用时,并没有直接重写service
方法,而是继承了HttpServlet
,重写了doGet
、doPost
等方法,而这期间又发生了什么呢。
首先,我们观察Servlet
这个接口:
1 2 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
类:
1 2 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
:
1 2 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
方法:
1 2 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);
具体再看该段重载方法:
1 2 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
方法:
1 2 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
处理请求做个流程图总结: