一、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 来做分发:

    

 

posted on 2021-08-06 11:16  格物致知_Tony  阅读(597)  评论(0编辑  收藏  举报