在之前的文章Servlet执行原理浅谈中对Servlet的整个原理做了大概介绍。我们知道客户端发送的请求是交给Servlet中的service方法进行处理。而在实际使用时,并没有直接重写service方法,而是继承了HttpServlet,重写了doGetdoPost等方法,而这期间又发生了什么呢。

首先,我们观察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方法,其他的几个方法并不常用。因此,就出现了以下两个实现类:

image-20201129170130519

首先我们看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);
}
// 其他方法省略
}

为了方便展示,我们只保留了doGetdoPost以及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种类型之一,就调用其相应的方法。

这里我们继续看doGetdoPost方法:

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中又继而调用更加具体的方法(doGetdoPost…)来为我们处理请求。

现在对整个Servlet处理请求做个流程图总结:

请求处理过程


Comment