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