一、Servlet 的体系结构
1、Servlet 的体系结构示意图
2、Servlet 类的继承体系
二、体系结构剖析
1、Servlet 接口
Servlet 这个接口,里面只是定义了规范(面向接口编程),如果直接实现这个接口,需要重写里面所有的方法,但是经常使用 service() 方法,其他的不常用。其中定义了五个抽象方法,如下:
2、GenericServlet 抽象类
GenericServlet 抽象类将其继承的接口中的方法做了默认空实现,将service()方法继续作为抽象方法,供其子类去做实现:
GenericServlet 继承结构:
方法列表:
可以看到 GenericServlet 类对 Servlet接口和ServletConfig接口中的方法做了实现,保留 service() 抽象方法供其子类实现。
ServletConfig 接口
在GenericServlet 类中还有一个属性 ServletConfig,这是一个关于当前 servlet 的配置类。
关于源码:
1 private transient ServletConfig config;
2
3 public void init(ServletConfig config) throws ServletException {
4 this.config = config;
5 this.init();
6 }
7 public ServletConfig getServletConfig() {
8 return config;
9 }
在 init(ServletConfig) 中通过参数的 config 来给属性赋值,并且还提供了一个 getServletConfig() 方法来获取此配置对象。
同时还有一个 getServletContext() 方法,也可以帮助我们更方便的获取 ServletContext 对象。
3、HttpServlet 抽象类
HttpServlet 继承了 GenericServlet 类,对 HTTP 协议的一种封装,简化操作,其中主要是对 service() 方法的重写操作。
HttpServlet 类结构:
HttpServlet 类方法列表:
本类中定义了多个常量和多个 do 系列的方法,为什么要这么做呢?
源码分析:
1 @Override
2 public void service(ServletRequest req, ServletResponse res)
3 throws ServletException, IOException
4 {
5 HttpServletRequest request;
6 HttpServletResponse response;
7
8 if (!(req instanceof HttpServletRequest &&
9 res instanceof HttpServletResponse)) {
10 throw new ServletException("non-HTTP request or response");
11 }
12
13 request = (HttpServletRequest) req;
14 response = (HttpServletResponse) res;
15
16 service(request, response);
17 }
18
19 //重载的 service 方法
20 protected void service(HttpServletRequest req, HttpServletResponse resp)
21 throws ServletException, IOException
22 {
23 String method = req.getMethod();
24
25 if (method.equals(METHOD_GET)) {
26 long lastModified = getLastModified(req);
27 if (lastModified == -1) {
28 // servlet doesn't support if-modified-since, no reason
29 // to go through further expensive logic
30 doGet(req, resp);
31 } else {
32 long ifModifiedSince = req.getDateHeader(HEADER_IFMODSINCE);
33 if (ifModifiedSince < lastModified) {
34 // If the servlet mod time is later, call doGet()
35 // Round down to the nearest second for a proper compare
36 // A ifModifiedSince of -1 will always be less
37 maybeSetLastModified(resp, lastModified);
38 doGet(req, resp);
39 } else {
40 resp.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
41 }
42 }
43
44 } else if (method.equals(METHOD_HEAD)) {
45 long lastModified = getLastModified(req);
46 maybeSetLastModified(resp, lastModified);
47 doHead(req, resp);
48
49 } else if (method.equals(METHOD_POST)) {
50 doPost(req, resp);
51
52 } else if (method.equals(METHOD_PUT)) {
53 doPut(req, resp);
54
55 } else if (method.equals(METHOD_DELETE)) {
56 doDelete(req, resp);
57
58 } else if (method.equals(METHOD_OPTIONS)) {
59 doOptions(req,resp);
60
61 } else if (method.equals(METHOD_TRACE)) {
62 doTrace(req,resp);
63
64 } else {
65 //
66 // Note that this means NO servlet supports whatever
67 // method was requested, anywhere on this server.
68 //
69
70 String errMsg = lStrings.getString("http.method_not_implemented");
71 Object[] errArgs = new Object[1];
72 errArgs[0] = method;
73 errMsg = MessageFormat.format(errMsg, errArgs);
74
75 resp.sendError(HttpServletResponse.SC_NOT_IMPLEMENTED, errMsg);
76 }
77 }
前面当用不同的请求方式访问服务器时,我们需要根据请求的方式,进行不同的分发。而这个类帮助我们强转了 ServletRequest 对象,实现了分发处理。
所以,HttpServlet 主要做了两件事:
(1)重写了父类的 service() 方法;
(2)重载了 service() 方法,完成分发处理;
在我们自定义 Servlet 程序时只需要继承HttpServlet 类,然后根据业务重写 doGet() 与 doPost() 方法即可。
4、自定义 Servlet 类
当我们自定义的 Servlet 程序继承了 HttpServlet 类时,就可以根据业务选择不同的请求方法重写对应的方法,然后由 HttpServlet 来做分发: