Servlet学习笔记【1】--- 背景和基础知识(CGI、Web服务器发展史、Servlet简介、任务、继承结构)

本文主要讲Servlet的基础知识和背景知识。

1 CGI简介

CGI(Common Gateway Interface 公共网关接口)是WWW技术中最重要的技术之一,有着不可替代的重要地位。CGI是外部应用程序(CGI程序)与WEB服务器之间的接口标准,是在CGI程序和Web服务器之间传递信息的过程。CGI规范允许Web服务器执行外部程序,并将它们的输出发送给Web浏览器,CGI将Web的一组简单的静态超媒体文档变成一个完整的新的交互式媒体。

Common Gateway Interface,简称CGI。在物理上是一段程序,运行在服务器上,提供同客户端HTML页面的接口。这样说大概还不好理解。那么我们看一个实际例子:现在的个人主页上大部分都有一个留言本。留言本的工作是这样的:先由用户在客户端输入一些信息,如评论之类的东西。接着用户按一下“发布或提交”(到目前为止工作都在客户端),浏览器把这些信息传送到服务器的CGI目录下特定的CGI程序中,于是CGI程序在服务器上按照预定的方法进行处理。在本例中就是把用户提交的信息存入指定的文件中。然后CGI程序将执行结果返回给服务器(webServer),然后服务器将结果返回给客户端,表示请求的任务已经结束。此时用户在浏览器里将看到“留言结束”的字样,整个过程结束。

2 Web服务器发展历史

通过服务器可以访问静态资源和动态资源。

静态资源就是一些图片、视频等文件。访问流程:读取磁盘文件到内存中--->启动IO流-->将文件内容以字符串形式返回给浏览器。

动态资源是一些代码,需要执行后将结果返回给浏览器端。而要在本地执行对应的代码,就需要有执行环境和标准接口规范(个人理解就是上边的CGI)。

1)早期CGI模式服务器

CGI模式的特点:是将服务端的动态资源基于进程(process)方法来运行。由于进程的执行非常耗费时间,且内存空间浪费,所以效率极其低下。

2)FastCGI模式服务器

所谓的fastCGI的模式其实就是当前的CGI模式中添加的一个pooling(资源池)的概念,在服务器启动时初始化固定的进程来提高处理客服端的请求的速度,但是该方法治标不治本。

3)Servlet模式服务器

技术特点:

与传统的CGI模式不同,Servlet运行模式改为单进程多线程的模式(线程程运行在进程中)。

单进程:服务器;

多线程:服务端的Servlet。

这样就大大提高了运行效率。

3 Servlet简介

Java Servlet 是运行在 Web 服务器或应用服务器上的程序,它是作为来自 Web 浏览器或其他 HTTP 客户端的请求和 HTTP 服务器上的数据库或应用程序之间的中间层。

使用 Servlet,您可以收集来自网页表单的用户输入,呈现来自数据库或者其他源的记录,还可以动态创建网页。

Java Servlet 通常情况下与使用 CGI(Common Gateway Interface,公共网关接口)实现的程序可以达到异曲同工的效果。但是相比于 CGI,Servlet 有以下几点优势:

  • 性能明显更好。
  • Servlet 在 Web 服务器的地址空间内执行。这样它就没有必要再创建一个单独的进程来处理每个客户端请求。
  • Servlet 是独立于平台的,因为它们是用 Java 编写的。
  • 服务器上的 Java 安全管理器执行了一系列限制,以保护服务器计算机上的资源。因此,Servlet 是可信的。
  • Java 类库的全部功能对 Servlet 来说都是可用的。它可以通过 sockets 和 RMI 机制与 applets、数据库或其他软件进行交互。

4 Servlet架构

下图显示了 Servlet 在 Web 应用程序中的位置。

5 Servlet任务

Servlet 执行以下主要任务:

  • 读取客户端(浏览器)发送的显式的数据。这包括网页上的 HTML 表单,或者也可以是来自 applet 或自定义的 HTTP 客户端程序的表单。
  • 读取客户端(浏览器)发送的隐式的 HTTP 请求数据。这包括 cookies、媒体类型和浏览器能理解的压缩格式等等。
  • 处理数据并生成结果。这个过程可能需要访问数据库,执行 RMI 或 CORBA 调用,调用 Web 服务,或者直接计算得出对应的响应。
  • 发送显式的数据(即文档)到客户端(浏览器)。该文档的格式可以是多种多样的,包括文本文件(HTML 或 XML)、二进制文件(GIF 图像)、Excel 等。
  • 发送隐式的 HTTP 响应到客户端(浏览器)。这包括告诉浏览器或其他客户端被返回的文档类型(例如 HTML),设置 cookies 和缓存参数,以及其他类似的任务。

6 Servlet的继承结构

在Tomcat项目包中,有个lib目录,下边有个servlet-api.jar文件包,该jar包就是Tomcat对Servlet的接口实现。通过解压和反编译后,可以查看里边的实现代码。

解压方式:将jar包扩展名改为rar,然后解压。

反编译方式:通过jd-gui.exe反编译工具实现将class文件反编译为可读的java代码文件。

通过上边解压和反编译,在servlet-apijavaxservlet文件夹下,我们可以看到Servlet.class,其反编译后代码如下:

 1 package javax.servlet;
 2 
 3 import java.io.IOException;
 4 
 5 public abstract interface Servlet
 6 {
 7   public abstract void init(ServletConfig paramServletConfig)
 8     throws ServletException;
 9 
10   public abstract ServletConfig getServletConfig();
11 
12   public abstract void service(ServletRequest paramServletRequest, ServletResponse paramServletResponse)
13     throws ServletException, IOException;
14 
15   public abstract String getServletInfo();
16 
17   public abstract void destroy();
18 }

GenericServlet.class反编译后代码如下:

 1 package javax.servlet;
 2 
 3 import java.io.IOException;
 4 import java.io.Serializable;
 5 import java.util.Enumeration;
 6 
 7 public abstract class GenericServlet
 8   implements Servlet, ServletConfig, Serializable
 9 {
10   private static final long serialVersionUID = 1L;
11   private transient ServletConfig config;
12 
13   public void destroy()
14   {
15   }
16 
17   public String getInitParameter(String name)
18   {
19     return getServletConfig().getInitParameter(name);
20   }
21 
22   public Enumeration<String> getInitParameterNames()
23   {
24     return getServletConfig().getInitParameterNames();
25   }
26 
27   public ServletConfig getServletConfig()
28   {
29     return this.config;
30   }
31 
32   public ServletContext getServletContext()
33   {
34     return getServletConfig().getServletContext();
35   }
36 
37   public String getServletInfo()
38   {
39     return "";
40   }
41 
42   public void init(ServletConfig config)
43     throws ServletException
44   {
45     this.config = config;
46     init();
47   }
48 
49   public void init()
50     throws ServletException
51   {
52   }
53 
54   public void log(String msg)
55   {
56     getServletContext().log(getServletName() + ": " + msg);
57   }
58 
59   public void log(String message, Throwable t)
60   {
61     getServletContext().log(getServletName() + ": " + message, t);
62   }
63 
64   public abstract void service(ServletRequest paramServletRequest, ServletResponse paramServletResponse)
65     throws ServletException, IOException;
66 
67   public String getServletName()
68   {
69     return this.config.getServletName();
70   }
71 }

在servlet-apijavaxservlethttp文件夹下,可以找到HttpServlet.class文件,反编译后内容如下:

 1 package javax.servlet.http;
 2 
 3 // ...省略代码
 4 import javax.servlet.GenericServlet;
 5 
 6 public abstract class HttpServlet extends GenericServlet
 7 {
 8   // ...省略代码
 9   
10   protected void doGet(HttpServletRequest req, HttpServletResponse resp)
11     throws ServletException, IOException
12   {
13     // ...省略实现代码
14   }
15 
16   protected long getLastModified(HttpServletRequest req)
17   {
18     return -1L;
19   }
20 
21   protected void doHead(HttpServletRequest req, HttpServletResponse resp)
22     throws ServletException, IOException
23   {
24     // ...省略实现代码
25   }
26 
27   protected void doPost(HttpServletRequest req, HttpServletResponse resp)
28     throws ServletException, IOException
29   {
30     // ...省略实现代码
31   }
32 
33   protected void doPut(HttpServletRequest req, HttpServletResponse resp)
34     throws ServletException, IOException
35   {
36     // ...省略实现代码
37   }
38 
39   protected void doDelete(HttpServletRequest req, HttpServletResponse resp)
40     throws ServletException, IOException
41   {
42     // ...省略实现代码
43   }
44 
45   private static Method[] getAllDeclaredMethods(Class<?> c)
46   {
47     // ...省略实现代码
48   }
49 
50   protected void doOptions(HttpServletRequest req, HttpServletResponse resp)
51     throws ServletException, IOException
52   {
53     Method[] methods = getAllDeclaredMethods(super.getClass());
54     // ...省略实现代码
55   }
56 
57   protected void doTrace(HttpServletRequest req, HttpServletResponse resp)
58     throws ServletException, IOException
59   {
60     String CRLF = "
";
61     StringBuilder buffer = new StringBuilder("TRACE ").append(req.getRequestURI()).append(" ").append(req.getProtocol());
62     // ...省略实现代码
63   }
64 
65   protected void service(HttpServletRequest req, HttpServletResponse resp)
66     throws ServletException, IOException
67   {
68     String method = req.getMethod();
69     long lastModified;
70     // ...省略实现代码
71   }
72 
73   private void maybeSetLastModified(HttpServletResponse resp, long lastModified)
74   {
75     if (resp.containsHeader("Last-Modified"))
76       return;
77     if (lastModified >= 0L)
78       resp.setDateHeader("Last-Modified", lastModified);
79   }
80 
81   public void service(ServletRequest req, ServletResponse res)
82     throws ServletException, IOException
83   {
84     // ...省略实现代码
85   }
86 }

从上边源码中可以发现:

servlet.class文件就是实现SUN公司JavaEE制定的Servlet标准接口的代码;

GenericServlet.class 中间层 抽象类 直接实现Servlet,并没有将Servlet所有方法实现,添加了一些自己的方法;

http目录下的HttpServlet继承了GenericServlet,该主要实现与http协议相关的接口(doPost、doGet、doPut、doDelete)。

GenericServlet存在的原因:解除http协议和Servlet之间的耦合。随着技术发展后续可能会替换http,改为其它协议。这样如果要切换,可复用的部分在GenericServlet中,并不需要重新开发,只需要将httpServlet基于新协议重新开发即可。这就是开闭原则,需要更改时,只需要修改一部分代码即可。

Servlet是基于Http协议的。

参考资料&内容来源:

百度百科:https://baike.baidu.com/item/CGI/607810?fr=aladdin&fromid=6717913&fromtitle=%EF%BC%A3%EF%BC%A7%EF%BC%A9

速学堂:http://www.sxt.cn/tomcat/1-1-1.html

菜鸟教程:http://www.runoob.com/servlet/servlet-intro.html

原文地址:https://www.cnblogs.com/zhaoweikai/p/9877222.html