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

时间:2024-01-07 11:09:02

本文主要讲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模式服务器

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

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 应用程序中的位置。

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

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-api\javax\servlet文件夹下,我们可以看到Servlet.class,其反编译后代码如下:

 package javax.servlet;

 import java.io.IOException;

 public abstract interface Servlet
{
public abstract void init(ServletConfig paramServletConfig)
throws ServletException; public abstract ServletConfig getServletConfig(); public abstract void service(ServletRequest paramServletRequest, ServletResponse paramServletResponse)
throws ServletException, IOException; public abstract String getServletInfo(); public abstract void destroy();
}

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

 package javax.servlet;

 import java.io.IOException;
import java.io.Serializable;
import java.util.Enumeration; public abstract class GenericServlet
implements Servlet, ServletConfig, Serializable
{
private static final long serialVersionUID = 1L;
private transient ServletConfig config; public void destroy()
{
} public String getInitParameter(String name)
{
return getServletConfig().getInitParameter(name);
} public Enumeration<String> getInitParameterNames()
{
return getServletConfig().getInitParameterNames();
} public ServletConfig getServletConfig()
{
return this.config;
} public ServletContext getServletContext()
{
return getServletConfig().getServletContext();
} public String getServletInfo()
{
return "";
} public void init(ServletConfig config)
throws ServletException
{
this.config = config;
init();
} public void init()
throws ServletException
{
} public void log(String msg)
{
getServletContext().log(getServletName() + ": " + msg);
} public void log(String message, Throwable t)
{
getServletContext().log(getServletName() + ": " + message, t);
} public abstract void service(ServletRequest paramServletRequest, ServletResponse paramServletResponse)
throws ServletException, IOException; public String getServletName()
{
return this.config.getServletName();
}
}

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

 package javax.servlet.http;

 // ...省略代码
import javax.servlet.GenericServlet; public abstract class HttpServlet extends GenericServlet
{
// ...省略代码 protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException
{
// ...省略实现代码
} protected long getLastModified(HttpServletRequest req)
{
return -1L;
} protected void doHead(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException
{
// ...省略实现代码
} protected void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException
{
// ...省略实现代码
} protected void doPut(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException
{
// ...省略实现代码
} protected void doDelete(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException
{
// ...省略实现代码
} private static Method[] getAllDeclaredMethods(Class<?> c)
{
// ...省略实现代码
} protected void doOptions(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException
{
Method[] methods = getAllDeclaredMethods(super.getClass());
// ...省略实现代码
} protected void doTrace(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException
{
String CRLF = "\r\n";
StringBuilder buffer = new StringBuilder("TRACE ").append(req.getRequestURI()).append(" ").append(req.getProtocol());
// ...省略实现代码
} protected void service(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException
{
String method = req.getMethod();
long lastModified;
// ...省略实现代码
} private void maybeSetLastModified(HttpServletResponse resp, long lastModified)
{
if (resp.containsHeader("Last-Modified"))
return;
if (lastModified >= 0L)
resp.setDateHeader("Last-Modified", lastModified);
} public void service(ServletRequest req, ServletResponse res)
throws ServletException, IOException
{
// ...省略实现代码
}
}

从上边源码中可以发现:

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协议的。

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

参考资料&内容来源:

百度百科: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