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-api\javax\servlet文件夹下,我们可以看到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-api\javax\servlet\http文件夹下,可以找到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 = "\r\n"; 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
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· 从HTTP原因短语缺失研究HTTP/2和HTTP/3的设计差异
· 三行代码完成国际化适配,妙~啊~