深入拆解TomcatJetty(一)

深入拆解Tomcat&Jetty(一)

专栏地址:https://time.geekbang.org/column/intro/100027701

1、Web容器是什么

早期的 Web 应用主要用于浏览新闻等静态页面,HTTP 服务器(比如 Apache、Nginx)向浏览器返回静态 HTML,浏览器负责解析 HTML,将结果呈现给用户。

随着互联网的发展,我们已经不满足于仅仅浏览静态页面,还希望通过一些交互操作,来获取动态结果,因此也就需要一些扩展机制能够让 HTTP 服务器调用服务端程序

于是 Sun 公司推出了 Servlet 技术。你可以把 Servlet 简单理解为运行在服务端的 Java 小程序,但是 Servlet 没有 main 方法,不能独立运行,因此必须把它部署到 Servlet 容器中,由容器来实例化并调用 Servlet。

而 Tomcat 和 Jetty 就是一个 Servlet 容器。为了方便使用,它们也具有 HTTP 服务器的功能,因此Tomcat 或者 Jetty 就是一个“HTTP 服务器 + Servlet 容器”,我们也叫它们 Web 容器。

其他应用服务器比如 JBoss 和 WebLogic,它们不仅仅有 Servlet 容器的功能,也包含 EJB 容器,是完整的 Java EE 应用服务器。从这个角度看,Tomcat 和 Jetty 算是一个轻量级的应用服务器。

2、Http协议

2.1、Http工作原理

HTTP 协议是浏览器与服务器之间的数据传送协议。作为应用层协议,HTTP 是基于 TCP/IP 协议来传递数据的(HTML 文件、图片、查询结果等),HTTP 协议不涉及数据包(Packet)传输,主要规定了客户端和服务器之间的通信格式。

假如浏览器需要从远程 HTTP 服务器获取一个 HTML 文本,在这个过程中,浏览器实际上要做两件事情。

  • 与服务器建立 Socket 连接。
  • 生成请求数据并通过 Socket 发送出去。

请求数据包含的内容:发送方意图(请求数据还是提交数据)+ 发送内容(我想请求的内容||我想提交的内容)

HTTP 协议的本质就是一种浏览器与服务器之间约定好的通信格式。约定了请求数据的存储格式。

在这里插入图片描述

Tomcat 和 Jetty 作为 HTTP 服务器,在这个过程中主要是处理 接受连接、解析请求数据、处理请求和发送响应这几个步骤。

HTTP 请求数据由三部分组成,分别是请求行、请求报头、请求正文。当这个 HTTP 请求数据到达 Tomcat 后,Tomcat 会把 HTTP 请求数据字节流解析成一个 Request 对象,这个 Request 对象封装了 HTTP 所有的请求信息。接着 Tomcat 把这个 Request 对象交给 Web 应用去处理,处理完后得到一个 Response 对象,Tomcat 会把这个 Response 对象转成 HTTP 格式的响应数据并发送给浏览器。

HTTP 的响应也是由三部分组成,分别是状态行、响应报头、报文主体

HTTP 是通信的方式,HTML 才是通信的目的,就好比 HTTP 是信封,信封里面的信(HTML)才是内容;但是没有信封,信也没办法寄出去。

2.2、Cookie和Session

Cookie 是 HTTP 报文的一个请求头,Web 应用可以将用户的标识信息或者其他一些信息(用户名、角色等)存储在 Cookie 中。用户经过验证之后,每次 HTTP 请求报文中都包含 Cookie,这样服务器读取这个 Cookie 请求头就知道用户是谁了。Cookie 本质上就是一份存储在用户本地的文件,里面包含了每次请求中都需要传递的信息

由于 Cookie 以明文的方式存储在本地,而 Cookie 中往往带有用户信息,这样就造成了非常大的安全隐患。而 Session 的出现解决了这个问题,Session 可以理解为***服务器***端开辟的存储空间,里面保存了用户的状态,用户信息以 Session 的形式存储在服务端。当用户请求到来时,服务端可以把用户的请求和用户的 Session 对应起来。那么 Session 是怎么和请求对应起来的呢?答案是通过 Cookie,浏览器在 Cookie 中填充了一个 Session ID 之类的字段用来标识请求。

具体工作过程是这样的:服务器在创建 Session 的同时,会为该 Session 生成唯一的 Session ID,通过 set-cookie 放到响应头里,然后浏览器写到 Cookie 里,当浏览器再次发送请求的时候,会将这个 Session ID 带上,服务器接受到请求之后就会依据 Session ID 找到相应的 Session,找到 Session 后,就可以在 Session 中获取或者添加内容了。而这些内容只会保存在服务器中,发到客户端的只有 Session ID,这样相对安全,也节省了网络流量,因为不需要在 Cookie 中存储大量用户信息。

在 Java 中,Session 是 Web 应用程序在调用 HttpServletRequest 的 getSession 方法时,由 Web 容器(比如 Tomcat)创建的。

2.3、如何理解Http的无状态

Http的无状态是指不同请求间协议内容无相关性,即本次请求与上次请求没有内容的依赖关系,本次响应也只针对本次请求的数据,至于服务器应用程序为用户保存的状态(Cookie、Session)是属于应用层,与协议是无关的。

https://developer.aliyun.com/article/846786

在 HTTP/1.0 时期,每次 HTTP 请求都会创建一个新的 TCP 连接,请求完成后之后这个 TCP 连接就会被关闭。这种通信模式的效率不高。

在 HTTP/1.1 中,引入了 HTTP 长连接的概念,使用长连接的 HTTP 协议,会在响应头加入 Connection:keep-alive。这样当浏览器完成一次请求后,浏览器和服务器之间的 TCP 连接不会关闭,再次访问这个服务器上的网页时,浏览器会继续使用这一条已经建立的连接,也就是说两个请求可能共用一个 TCP 连接。

Connection:keep-alive只是建立TCP层的状态,省去了下一次的TCP三次握手,而HTTP本身还是继续保持无状态。

应用程序其实一般不关心这次HTTP请求的TCP传输细节,只关心HTTP协议的内容,因此只要复用TCP连接时做好必要的数据重置,是不算有状态的。不过HTTP/1.1中的长连接没有解决 head of line blocking(线头阻塞),请求是按顺序排队处理的,前面的HTTP请求处理会阻塞后面的HTTP请求,虽然HTTP pipelining对连接请求做了改善,但是复杂度太大,并没有普及,以至于后面的连接必须等待前面的返回了才能够发送。这个问题直到HTTP/2.0采取二进制分帧编码方式才彻底解决。

  • HTTP 1.0
    买一个信封只能传送一个来回的信。
  • HTTP 1.1 keep–alive
    买一个信封可重复使用,但前提是得等到服务端把这个信封里的信处理完,并送回来!

REST的无状态

REST是一种架构风格:将网络上的信息实体看作是资源,可以是图片、文件、一个服务…资源用URI统一标识,URI中没有动词,这是因为它是资源的标识,那怎么操作这些资源呢,于是定义一些动作:GET、POST、PUT和DELETE。通过URI+动作来操作一个资源。所谓的无状态说的是,为了完成一个操作,请求里包含了所有信息,你可以理解为服务端不需要保存请求的状态,也就是不需要保存 Session ,没有 Session 的好处是带来了服务端良好的可伸缩性,方便 failover,请求被 LB 转到不同的 server 实例上没有差别。从这个角度看,正是有了REST架构风格的指导,才有了HTTP的无状态特性,顺便提一下,REST 和 HTTP1.1 出自同一人之手。但是理想是丰满的,现实是骨感的,为了方便开发,大多数复杂的 Web 应用不得不在服务端保存 Session。为了尽量减少 Session 带来的弊端,往往将 Session 集中存储到 Redis 上,而不是直接存储在 server 实例上。

3、Servlet容器

3.1、为什么会出现Servlet容器

浏览器发给服务端的是一个 HTTP 格式的请求,HTTP 服务器收到这个请求后,需要调用服务端程序来处理,所谓的服务端程序就是你写的 Java 类,一般来说不同的请求需要由不同的 Java 类来处理。

HTTP服务器该怎么知道去寻找哪个类的哪个方法处理呢?为了避免HTTP服务器和业务类的耦合问题,一伙人就定义了一个接口,各种业务类都必须实现这个接口,这个接口就叫 Servlet 接口,有时我们也把实现了 Servlet 接口的业务类叫作 Servlet。对于特定的请求,HTTP 服务器如何知道由哪个 Servlet 来处理呢?Servlet 又是由谁来实例化呢?显然 HTTP 服务器不适合做这个工作,否则又和业务类耦合了。于是,还是那伙人又发明了 Servlet 容器,Servlet 容器用来加载和管理业务类。HTTP 服务器不直接跟业务类打交道,而是把请求交给 Servlet 容器去处理,Servlet 容器会将请求转发到具体的 Servlet,如果这个 Servlet 还没创建,就加载并实例化这个 Servlet,然后调用这个 Servlet 的接口方法。因此 Servlet 接口其实是 Servlet 容器跟具体业务类之间的接口

在这里插入图片描述

作为 Java 程序员,如果我们要实现新的业务功能,只需要实现一个 Servlet,并把它注册到 Tomcat(Servlet 容器)中,剩下的事情就由 Tomcat 帮我们处理了。

3.2、Servlet接口

Servlet接口定义了下面五个方法:

public interface Servlet {
    void init(ServletConfig config) throws ServletException;
    
    ServletConfig getServletConfig();
    
    void service(ServletRequest req, ServletResponse res)throws ServletException, IOException;
    
    String getServletInfo();
    
    void destroy();
}

其中最重要是的 service 方法,具体业务类在这个方法里实现处理逻辑。这个方法有两个参数:ServletRequest 和 ServletResponse。ServletRequest 用来封装请求信息,ServletResponse 用来封装响应信息,因此本质上这两个类是对通信协议的封装。(HTTP1.0、HTTP1.1、HTTP2.0…)

当客户请求某个资源时,HTTP 服务器会用一个 ServletRequest 对象把客户的请求信息封装起来,然后调用 Servlet 容器的 service 方法,Servlet 容器拿到请求后,根据请求的 URL 和 Servlet 的映射关系,找到相应的 Servlet,如果 Servlet 还没有被加载,就用反射机制创建这个 Servlet,并调用 Servlet 的 init 方法来完成初始化,接着调用 Servlet 的 service 方法来处理请求,把 ServletResponse 对象返回给 HTTP 服务器,HTTP 服务器会把响应发送给客户端。

在这里插入图片描述

Servlet 容器会实例化和调用 Servlet,那 Servlet 是怎么注册到 Servlet 容器中的呢?一般来说,我们是以 Web 应用程序的方式来部署 Servlet 的,而根据 Servlet 规范,Web 应用程序有一定的目录结构,在这个目录下分别放置了 Servlet 的类文件、配置文件以及静态资源,Servlet 容器通过读取配置文件,就能找到并加载 Servlet。

| -  MyWebApp
      | -  WEB-INF/web.xml        -- 配置文件,用来配置 Servlet 等
      | -  WEB-INF/lib/           -- 存放 Web 应用所需各种 JAR 包
      | -  WEB-INF/classes/       -- 存放你的应用类,比如 Servlet 类
      | -  META-INF/              -- 目录存放工程的一些信息
3.3、拓展机制

引入了 Servlet 规范后,开发者不需要关心 Socket 网络通信、不需要关心 HTTP 协议,也不需要关心业务类是如何被实例化和调用的,因为这些都被 Servlet 规范标准化了,只要关心怎么实现业务逻辑。但是如果这个规范不能满足你的业务的个性化需求,就有问题了,因此设计一个规范或者一个中间件,要充分考虑到可扩展性。Servlet 规范提供了两种扩展机制:FilterListener

Filter是过滤器,这个接口允许你对请求和响应做一些统一的定制化处理,比如你可以根据请求的频率来限制访问,或者根据国家地区的不同来修改响应内容。过滤器的工作原理是这样的:Web 应用部署完成后,Servlet 容器需要实例化 Filter 并把 Filter 链接成一个 FilterChain。当请求进来时,获取第一个 Filter 并调用 doFilter 方法,doFilter 方法负责调用这个 FilterChain 中的下一个 Filter。

Listener是监听器,这是另一种扩展机制。当 Web 应用在 Servlet 容器中运行时,Servlet 容器内部会不断的发生各种事件,如 Web 应用的启动和停止、用户请求到达等。 Servlet 容器提供了一些默认的监听器来监听这些事件,当事件发生时,Servlet 容器会负责调用监听器的方法。当然,你可以定义自己的监听器去监听你感兴趣的事件,将监听器配置在 web.xml 中。比如 Spring 就实现了自己的监听器,来监听 ServletContext 的启动事件,目的是当 Servlet 容器启动时,创建并初始化全局的 Spring 容器。

  • Filter 是干预过程的,它是过程的一部分,是基于过程行为的。
  • Listener 是基于状态的,任何行为改变同一个状态,触发的事件是一致的。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/893784.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Google play开发者账号被封,申诉就有机会,别不信

在谷歌上架,开发者账号被封对很多开发者来说已经是家常便饭了,虽说一直都有在流传申诉没有用。别灰心啊,申诉就有机会,不少开发者都申诉成功了。 尤其是用一个少一个、价值好几个w的老号,不申诉就认栽实在是太亏了&…

【黑马点评优化】之使用Caffeine+Redis实现应用级二层缓存

【黑马点评优化】之使用CaffeineRedis实现应用级二层缓存 1 缓存雪崩定义及解决方案2 为什么要使用多级缓存3 RedisCaffeine实现应用层二级缓存原理4 利用CaffeineRedis解决Redis突然宕机导致的缓存雪崩问题4.1 pom.xml文件引入相关依赖4.2 本地缓存配置类4.3 修改ShopServiceI…

大有期货携手云轴科技ZStack 获“鼎新杯”数字化转型典型案例二等奖

近日,由中国通信标准化协会主办、中国信息通信研究院(简称“中国信通院”)承办、中国通信企业协会支持的“2024数字化转型发展大会”在北京召开。本届大会以“拥抱数智化无限可能”为主题,会上公布了第三届“鼎新杯”数字化转型应…

Centos 7.9NFS搭建

原创作者:运维工程师 谢晋 Centos 7.9NFS搭建 NFS服务端安装客户机访问共享配置 NFS服务端安装 SSH连接系统登录到服务端安装nfs服务 # yum -y install nfs-utils2. 安装完成后,查看需要共享的目录,这边共享的是/home目录,如…

Selenium - 用这个力量做任何你想做的事情

Chrome DevTools 简介 Chrome DevTools 是一组直接内置在基于 Chromium 的浏览器(如 Chrome、Opera 和 Microsoft Edge)中的工具,用于帮助开发人员调试和研究网站。 借助 Chrome DevTools,开发人员可以更深入地访问网站&#xf…

苹果正式宣布:iPhone全面开放近场通信(Near Field Communication,简称NFC)【使用安全元件提供app内NFC数据交换功能】

文章目录 引言I iPhone的NFC功能开发者用户数据交换的体验革新安全与隐私II 知识扩展:近场通信(NFC)技术钱包NFC开关打开读取NFC标签(NFC tags )权限demo引言 2014年iPhone 6开始,苹果首次引入了NFC功能,但最初只允许自家的Apple Pay进行移动支付。慢慢地适配了交通卡,增…

RAG拉满-上下文embedding与大模型cache

无论怎么选择RAG的切分方案,仍然切分不准确。 最近,anthropics给出了补充上下文的embedding的方案,RAG有了新的进展和突破。 从最基础的向量查询,到上下文embedding,再到rerank的测试准确度都有了明显的改善&#xf…

Excel:vba实现合并工作簿中的表

A、B、C这三个工作簿的数据都在sheet1,表头一样 Sub MergeWorkbooks()Dim FolderPath As StringDim FileName As StringDim wb As WorkbookDim ws As WorksheetDim mainWb As WorkbookDim mainWs As WorksheetDim lastRow As LongDim lastcol As LongDim pasteRang…

双足机器人远程操作与动态运动同步研究

在当前的机器人技术中,双足机器人因其能够在复杂环境中灵活行动而备受关注。随着技术的进步,研究者们致力于开发能够与人类操作员实现高效同步的双足机器人,特别是在应对自然灾害或人为危险等紧急情况下的应用。 项目背景 尽管人工智能领域取…

Missing classes detected while running R8报错解决方案

Android 打包release版本时报错如下: > Task :printlib:minifyReleaseWithR8 FAILED AGPBI: {"kind":"error","text":"Missing classes detected while running R8. Please add the missing classes or apply additional ke…

在限制条件下求1+2+3+...+n

一:题目 二:代码 前提: A:静态成员和静态函数的性质 1.静态成员为所有类对象所共享,不属于某个具体的对象,存放在静态区 2. 静态成员变量必须在类外定义,定义时不添加static关键字&#xff0…

大模型生图安全疫苗注入赛题解析(DataWhale组队学习)

引言 大家好,我是GISer Liu😁,一名热爱AI技术的GIS开发者。本系列文章是我跟随DataWhale 2024年10月实践赛的大模型生图安全疫苗注入赛道;本文主要整理本次赛事的基本流程和优化方法。💕💕😊 一…

使用node.js控制CMD命令——修改本机IP地址

设置每次打开cmd命令行窗口都是以管理员身份运行: 1. 按下Ctrl Shift Esc键组合,打开任务管理器。 2. 在任务管理器中,点击“文件”菜单,选择“运行新任务”。 3. 在“创建新任务”对话框中,输入cmd,勾…

1.2024.10.17

2024.10.17 总体规划 总体规划 写这个合集的原因 记录自己入行之前成长过程。本人菜鸟一枚,大佬不喜勿喷。 目前的规划 更新频率 尽量一天一更,会更新之前发布的笔记,争取笔记更加完善。 学习方法 目标 通过面试,成功入行嵌…

移情别恋c++ ദ്ദി˶ー̀֊ー́ ) ——14.哈希(1)

移情别恋c ദ്ദി˶ー̀֊ー́ ) ——14.哈希(1) unordered系列关联式容器 在C98中,STL提供了底层为红黑树结构的一系列关联式容器,在查询时效率可达到 l o g 2 N log_2 N log2​N,即最差情况下需要比较红黑树的高度次…

新兴的安全职业挑战

我们经常与安全专业人士交谈,他们希望在努力提升职业发展的同时提高自己的价值并克服组织内部的挑战。在这些谈话中,花费大量时间讨论公司未来将面临的安全问题并不罕见。 安全领导者希望为问题制定计划并获得领导层对其计划的支持。这通常意味着实施修…

【RoadRunner】自动驾驶模拟3D场景构建 | 软件简介与视角控制

💯 欢迎光临清流君的博客小天地,这里是我分享技术与心得的温馨角落 💯 🔥 个人主页:【清流君】🔥 📚 系列专栏: 运动控制 | 决策规划 | 机器人数值优化 📚 🌟始终保持好奇心&…

IDEA下载安装

文章目录 1、下载安装包2、安装IDEA3、全局配置4、安装插件5、关闭合并菜单栏 1、下载安装包 IDEA官网下载最新IDEA。 上面的ULtimate是旗舰版,试用30天,之后是需要收费的,下面黑色区域的Community是社区版,功能不如旗舰版丰富&a…

nuScenes数据集使用的相机的外参和内参

因为需要用不同数据集测试对比效果,而一般的模型代码里实现的检测结果可视化都是使用open3d的Visualizer在点云上画的3d框,展示出来的可视化效果很差,可能是偷懒,没有实现将检测结果投影到各相机的图像上,所以检测效果…

删除链表的倒数第 N 个结点 | LeetCode-19 | 双指针 | 递归 | 栈 | 四种方法

🙋大家好!我是毛毛张! 🌈个人首页: 神马都会亿点点的毛毛张 这道题还可以用递归法,你想到了吗?毛毛张介绍四种方法 LeetCode链接:19. 删除链表的倒数第 N 个结点 1.题目描述 给你一个链表&a…