板块一 Servlet编程:第二节 Servlet的实现与生命周期 来自【汤米尼克的JAVAEE全套教程专栏】

板块一 Servlet编程:第二节 Servlet的实现与生命周期

  • 一、Servlet相关概念
    • Serlvet的本质
  • 二、中Web项目中实现Servlet规范
    • (1)在普通的Java类中继承HttpServlet类
    • (2)重写service方法
      • 编辑项目对外访问路径
  • 二、Servlet工作流程
  • 三、其它实现Servlet规范的方式
    • (1)继承自GenericServlet 类
    • (2)实现Servlet接口
    • (3)在HttpServlet中直接重写doGet()和doPost()方法
  • 四、Servlet生命周期

在上一节的内容中,我们已经系统的学习了HTTP的相关概念、知道了GET和POST请求在服务器上的运行原理、请求响应在服务器中究竟是怎样运行的,从这一节开始我们将系统的学习实现Servlet的完整过程

一、Servlet相关概念

Serlvet的本质

  • 当编写Java程序想要在网上实现聊天、发帖、这样一些的交互功能,普通Java技术是非常复杂的,试想要从底层搭建出一整个服务层的代码有多复杂?并且每个人搭建的底层还不一样,为了解决这个问题,sun公司就提供了Serlvet这种技术供我们使用。Servlet是Server与Applet的缩写,是服务端小程序的意思,本质上就是一个遵循Servlet开发的Java类,由服务器调用,在服务器端运行,它的创建、使用、销毁都由Servlet容器进行管理,其常见容器有很多,如Tomcat,Jetty,WebLogic Server,WebSphere,JBoss等等(在Tomcat的集成这一节中我们已经详尽的学习了Tomcat),更奇怪的是Servlet没有main()方法,本质上我们可以想象Servlet通过某种注入回调方法与Servlet容器取得联系,从而代替我们在Servlet中书写main()函数
    在这里插入图片描述
  • Servlet与HTTP紧密联系,可以处理与HTTP协议相关的所有内容,这是Servlet应用广泛的原因之一
  • 实际上在运行JSP时,服务器底层将JSP编译成一个Java类,这个类就是Servlet,因此可以说JSP就是Servlet(详见JSP追根溯源小节)
  • Servlet在 JAVA WEB项目中的位置,它就是我们常说的后端

在这里插入图片描述

  • 编程学习越往后越是如此,我们能做的其实很有限。大部分工作框架都已经帮我们做了。只
    要我们实现xx接口,它会帮我们创建实例,然后搬运(接口注入)到它合适的位置,然后一套既定
    的流程下来执行到创建我们需要的实例

二、中Web项目中实现Servlet规范

我们已经在板块零的第二节中创建了Java Web项目;又在板块零的第三节中成功把Tomcat集成到IDEA中,现在我们就在这个Web项目中实现Servlet规范

(1)在普通的Java类中继承HttpServlet类

在www.caijiyuan包中创建一个普通的Java类
helloServlet.java
在这里插入图片描述
此类继承HttpServlet类,还记得继承怎么写吗:extends
在这里插入图片描述

(2)重写service方法

在上一节中我们详细学习了请求响应在服务器中究竟是怎样运行的,而在Servlet中请求响应就是通过HttpServlet类中的service方法实现的,service方法有两个形参(Request,Rrsponse)分别对应请求、响应
在HttpServlet类中,IDEA重写方法的快捷键是Ctrl+O在这里插入图片描述
但我们发现有两个service,它们的区别是什么?
先来看第一个,HttpServlet的service()方法

protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {//获取http request的method参数,其实就是html的form标签  //中method属性对应的字符串 String method = req.getMethod();long errMsg;//判断请求方式if(method.equals("GET")) {//获取最后被修改时间 errMsg = this.getLastModified(req);if(errMsg == -1L) {/**如果servlet不支持http request header的if-modified-since属性 * 则继续处理 **/  this.doGet(req, resp);} else {//如果支持这个属性 long ifModifiedSince;try {ifModifiedSince = req.getDateHeader("If-Modified-Since");} catch (IllegalArgumentException var9) {ifModifiedSince = -1L;}/** * 如果客户端的文件最后修改时间和服务器端的文件最后修改时间一致则返回304不需要修改状态 * 这样服务器就不返回html,浏览器读取本地缓存文件,否则重新获取服务器端的对应html文件 **/  if(ifModifiedSince < errMsg / 1000L * 1000L) {this.maybeSetLastModified(resp, errMsg);this.doGet(req, resp);} else {resp.setStatus(304);}}} else if(method.equals("HEAD")) {errMsg = this.getLastModified(req);this.maybeSetLastModified(resp, errMsg);this.doHead(req, resp);} else if(method.equals("POST")) {this.doPost(req, resp);} else if(method.equals("PUT")) {this.doPut(req, resp);} else if(method.equals("DELETE")) {this.doDelete(req, resp);} else if(method.equals("OPTIONS")) {this.doOptions(req, resp);} else if(method.equals("TRACE")) {this.doTrace(req, resp);} else {//如果请求不是以上的所有请求方式,该方法就会响应501错误,也就是不支持这种请求String errMsg1 = lStrings.getString("http.method_not_implemented");Object[] errArgs = new Object[]{method};errMsg1 = MessageFormat.format(errMsg1, errArgs);resp.sendError(501, errMsg1);}}

这是第二个ServletRequest

public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException {HttpServletRequest request;HttpServletResponse response;try {request = (HttpServletRequest)req;response = (HttpServletResponse)res;} catch (ClassCastException var6) {throw new ServletException("non-HTTP request or response");}this.service(request, response);
}

原来只有第二个 ServletRequest service方法是由Tomcat自动调用,它将接收的客户端请求转交给HttpServlet中的第一个HttpServletRequest protected service方法,此保护类型的service方法再把将请求分发给doPost()doGet()方法进行下一步处理
因此这里就Request/Response俩个形参而言,重写调用第一个或第二个service方法的效果应该是一样的,此处我们直接重写第一个,也就是 HttpServletRequest protected service
在这里插入图片描述

编辑项目对外访问路径

我们还应将项目对外访问路径(就是在服务器中此项目的站点名)更改为自己想要的样子
在这里插入图片描述此处我更改为与包名一致/www.caijiyuan
在这里插入图片描述

注意:我们还应在类前设置注解@WebServlet("/helloServlet"),告诉服务器当前资源在站点下的真实路径

helloServlet.java中写入测试内容

package www.caijiyuan;import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;@WebServlet("/helloServlet")
public class helloServlet extends HttpServlet {@Overrideprotected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//        super.service(req, resp);//打印内容在控制台System.out.println("Hello Servlet with terminal");//通过流输出数据到浏览器resp.getWriter().write( "Hello Servlet with brower");}
}

启动服务器在浏览器中访问得

在这里插入图片描述
在控制台得
在这里插入图片描述

二、Servlet工作流程

那么HttpServletRequest request请求是在服务器中是怎样接受到的呢?
即是上一节中详解过的请求头的功劳

在这里插入图片描述
当请求进入服务器时

  1. 服务器会通过请求头键值对中的Host中的localhost找到主机本机
  2. 通过8080端口确定本机中占用端口的程序Tomcat
  3. 通过请求行中的"/www.caijiyuan"确定是Tomcat下的哪个站点
  4. 通过"/helloServlet"确定是当前站点下的那个资源路径

找到资源路径后,如果服务器是第一次被访问就会创建一个Servlet否则就会调用service方法生成request对象来处理会话中的请求;接受到请求后经过设定的代码生成response对象保存响应内容返回给客户端(浏览器),这就是Servlet工作的流程

三、其它实现Servlet规范的方式

(1)继承自GenericServlet 类

对于一个 Servlet 类,我们日常最常用的方法是继承自 HttpServlet 类,实际上,HttpServlet是扩展了GenericServlet 类。GenericServlet 类实现了Servlet,ServletConfig和Serializable接口。它主要完成了这些任务:

  • 将 init() 中的 ServletConfig 赋给一个类级变量,可以由 getServletConfig 获得;
  • 为 Servlet 所有方法提供默认实现的接口(除了service方法);
  • 可以直接调用 ServletConfig 中的方法;
    它的基本结构如下:
abstract class GenericServlet implements Servlet,ServletConfig{//GenericServlet通过将ServletConfig赋给类级变量private trServletConfig servletConfig;public void init(ServletConfig servletConfig) throws ServletException {this.servletConfig=servletConfig;/*自定义init()的原因是:如果子类要初始化必须覆盖父类的init() 而使它无效 这样this.servletConfig=servletConfig不起作用 这样就会导致空指针异常 这样如果子类要初始化,可以直接覆盖不带参数的init()方法 */this.init();}//自定义的init()方法,可以由子类覆盖  //init()不是生命周期方法public void init(){}//实现service()空方法,并且声明为抽象方法,强制子类必须实现service()方法 public abstract void service(ServletRequest request,ServletResponse response) throws ServletException,java.io.IOException{}//实现空的destroy方法public void destroy(){ }
}

可以看到如果继承这个类的话,我们必须重写 service() 方法来对处理请求
继承自GenericServlet 类实现Servlet

package www.caijiyuan;import javax.servlet.GenericServlet;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebServlet;
import java.io.IOException;@WebServlet("/Servlet_Gener")
public class Servlet_Gener extends GenericServlet {@Overridepublic void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {//打印内容在控制台System.out.println("Hello Servlet with terminal");//通过流输出数据到浏览器servletResponse.getWriter().write( "Hello Servlet with brower");}
}

启动服务器后在浏览器中访问得

在这里插入图片描述

(2)实现Servlet接口

除了两个继承抽象类实现Servlet的接口,还有一个通过实现interface Servlet来实现Servlet规范的方法

在这里插入图片描述

实例
创建类Servlet_imp.java ,使其实现Servlet接口
在这里插入图片描述
IDEA中使用快捷键Alt+Shift+Enter实现方法,在service()方法中添加测试代码,并且在类前添上@WebServlet()注释

package www.caijiyuan;import javax.servlet.*;
import javax.servlet.annotation.WebServlet;
import java.io.IOException;@WebServlet("/Servlet_imp")
public class Servlet_imp implements Servlet {@Overridepublic void init(ServletConfig servletConfig) throws ServletException {}@Overridepublic ServletConfig getServletConfig() {return null;}@Overridepublic void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {//通过流输出数据到浏览器servletResponse.getWriter().write( "Hello Servlet with brower");}@Overridepublic String getServletInfo() {return null;}@Overridepublic void destroy() {}
}

访问浏览器同样可以得到
在这里插入图片描述

(3)在HttpServlet中直接重写doGet()和doPost()方法

我们在调用HttpServlet中service方法时,底层实际上是判断GET请求还是POST请求从而分别调用doGet()和doPost()方法

protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {String method = req.getMethod();long lastModified;if (method.equals("GET")) {lastModified = this.getLastModified(req);if (lastModified == -1L) {this.doGet(req, resp);} else {long ifModifiedSince;try {ifModifiedSince = req.getDateHeader("If-Modified-Since");} catch (IllegalArgumentException var9) {ifModifiedSince = -1L;}if (ifModifiedSince < lastModified / 1000L * 1000L) {this.maybeSetLastModified(resp, lastModified);this.doGet(req, resp);} else {resp.setStatus(304);}}} else if (method.equals("HEAD")) {lastModified = this.getLastModified(req);this.maybeSetLastModified(resp, lastModified);this.doHead(req, resp);} else if (method.equals("POST")) {this.doPost(req, resp);} else if (method.equals("PUT")) {this.doPut(req, resp);} else if (method.equals("DELETE")) {this.doDelete(req, resp);} else if (method.equals("OPTIONS")) {this.doOptions(req, resp);} else if (method.equals("TRACE")) {this.doTrace(req, resp);} else {String errMsg = lStrings.getString("http.method_not_implemented");Object[] errArgs = new Object[]{method};errMsg = MessageFormat.format(errMsg, errArgs);resp.sendError(501, errMsg);}}

实例
创建类Servlet_do.java使其继承自HttpServlet,然后重写doGet()和doPost()方法
在这里插入图片描述
通过上一节我们已经知道了浏览器访问地址是使用GET方法,所以我们在doGet()中添加测试代码,并且在类前添上@WebServlet()注释

package www.caijiyuan;import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;@WebServlet("/Servlet_do")
public class Servlet_do extends HttpServlet {@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//        super.doGet(req, resp);//通过流输出数据到浏览器resp.getWriter().write( "Hello Servlet with brower");}@Overrideprotected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//        super.doPost(req, resp);}
}

访问浏览器同样可以得到
在这里插入图片描述

以上三种方式都可以实现Servlet规范,使得普通Java类升级成Servlet类,但最简便的方式还是第一种,也就是继承自HttpServlet类

四、Servlet生命周期

有了以上的知识储备,我们就可以梳理一下Servlet的整个生命周期了:由于Servlet没有main()方法,不能独立运行,它的运行完全由Servlet引擎来控制和调度,所谓生命周期,指的就是Servlet容器何时创建 Servlet实例、何时调用其方法进行请求的处理、何时并销毁其实例的整个过程。

  • 实例和初始化时机:当请求到达容器时,容器查找该 Servlet对象是否存在,如果不存在,则会创建实例并进行初始化,如果存在则会直接调用service()方法
  • 就绪/调用/服务阶段:当有请求到达容器,容器调用Servlet对象的 service()方法,此方法在整个生命周期中可以被多次调用;HttpServlet的 service()方法则会依据请求方式来调用doGet()或者doPost()方法。但是,这两个do方法默认情况下,会抛出异常,需要子类去override
  • 销毁时机:当容器关闭时(应用程序停止时),会将程序中的Servlet实例进行销毁。上述的生命周期可以通过Servlet 中的生命周期方法来观察。在Servlet 中有三个生命周期方法,不由用户手动调用,而是在特定的时机由容器自动调用

观察这三个生命周期方法即可观察到Servlet的生命周期

init方法,在Servlet 实例创建之后执行(证明该Servlet有实例创建了)

public void init() throws ServletException {System.out.println("创建实例调用");
}

service 方法,每次有请求到达某个Servlet 方法时执行,用来处理请求(证明该Servlet 进行服务了)

protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {System.out.println("service方法调用了");
}

destroy 方法,Servlet实例销毁时执行(证明该Servlet的实例被销毁了)

public void destroy() {System.out.println("实例被销毁了");
}

实例

启动服务器在浏览器中访问项目得
在这里插入图片描述
在控制台输出,即是在浏览器访问项目时调用了init()方法(只会被调用一次init()),并且紧接着接受请求调用了service方法
在这里插入图片描述
接着关闭Tomcat服务器,在控制台输出
在这里插入图片描述
Servlet的生命周期,可以更详细的分为四步:Servlet类加载 – >实例化 – >服务 – >销毁
下面我们描述一下Tomcat与Servlet是如何工作的,看看下面的时序图:
在这里插入图片描述

  1. Web Client 向Servlet容器(Tomcat)发出Http请求
  2. Servlet 容器接收Web Client的请求
  3. Servlet 容器创建一个HttpServletRequest对象,将Web Client请求的信息封装到这个对象中
  4. Servlet 容器创建一个HttpServletResponse 对象
  5. Servlet 容器调HttpServlet对象service 方法,把Request与Response作为参数,传给HttpServlet
  6. HttpServlet 调用HttpServletRequest对象的有关方法,获取Http请求信息
  7. HttpServlet 调用HttpServletResponse对象的有关方法,生成响应数据
  8. Servlet 容器把HttpServlet的响应结果传给Web Client

以上就是此小节的所有内容,我们系统的学习了Servlet的概念、实现Servlet规范的多个方法、Servlet的工作流程、生命周期等,为之后Servlet具体对象学习打下了坚实的基础。从下一节开始我们将学习service方法两个形参之一:HttpServletRequest实例的具体操作

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

六、Redis之数据持久化及高频面试题

6.1 数据持久化 官网文档地址&#xff1a;https://redis.io/docs/manual/persistence/ Redis提供了主要提供了 2 种不同形式的持久化方式&#xff1a; RDB&#xff08;Redis数据库&#xff09;&#xff1a;RDB 持久性以指定的时间间隔执行数据集的时间点快照。AOF&#xff0…

在微信公众平台怎么实现报名缴费链接_轻松几步,微信报名缴费全搞定!

在快节奏的现代生活中&#xff0c;人们越来越追求高效便捷的服务体验。传统的报名缴费方式&#xff0c;如现场排队、银行转账等&#xff0c;不仅耗费大量时间&#xff0c;还可能因为各种原因造成不便。如今&#xff0c;随着微信公众平台的普及和发展&#xff0c;我们有了更加简…

Android的常用Drawable讲解

今天来讲讲Android开发中水都绕不开的东西----drawable。最常使用的莫过于通过XML所声明的Drawable作为View背景&#xff0c;通过代码创建的应用场景则较少。其有着使用简单&#xff0c;比自定义view的成本要低的特点。同时&#xff0c;非图片类型的drawable占用空间较小&#…

OK-Robot机器人实现零样本算法 可在非结构化环境下完成拾取与放置任务

纽约大学的机器人专家团队与Meta人工智能学院研发人员共同合作开发了一种新型机器人&#xff0c;该机器人具备在非结构化环境下的认知能力&#xff0c;可在陌生房间利用视觉语言模型&#xff08;VLMs&#xff09;&#xff0c;进行物品的抓取与放置。在论文当中&#xff0c;该团…

NC6X单点登录设计文档说明

前言 因为业务场景需要&#xff0c;第三方系统有些工作需要经常到NC系统里做&#xff0c;如果每次去NC系统做业务单据&#xff0c;都需要反复登录&#xff0c;导致客户使用体验不是很好&#xff0c;所以需要开发实现从第三方系统单点登录到NC系统&#xff0c;提高客户满意度。 …

四、OpenAI之文本生成模型(Text Generation)

文本生成模型 OpenAI的文本生成模型(也叫做生成预训练的转换器(Generative pre-trained transformers)或大语言模型)已经被训练成可以理解自然语言、代码和图片的模型。模型提供文本的输出作为输入的响应。对这些模型的输入内容也被称作“提示词”。设计提示词的本质是你如何对…

C# CAD2016获取数据操作BlockTableRecord、Polyline、DBObject

一、数据操作说明 //DBObject 基础类 DBObject dbObj (DBObject)tr.GetObject(outerId, OpenMode.ForRead); //Polyline 线段类 Polyline outerPolyline (Polyline)tr.GetObject(outerId, OpenMode.ForRead); //BlockTableRecord 块表类 BlockTableRecord modelSpace (Bloc…

Excel练习:折线图突出最大最小值

Excel练习&#xff1a;折线图突出最大最小值 ​​ 要点&#xff1a;NA值在折现图中不会被绘制&#xff0c;看似一条线&#xff0c;实际是三条线。换成0值和""都不行。 ‍ 查看所有已分享Excel文件-阿里云 ‍ 学习的这个视频&#xff1a;Excel折线图&#xff0c…

Hive on Spark配置

前提条件 1、安装好Hive&#xff0c;参考&#xff1a;Hive安装部署-CSDN博客 2、下载好Spark安装包&#xff0c;链接&#xff1a;https://pan.baidu.com/s/1plIBKPUAv79WJxBSbdPODw?pwd6666 3、将Spark安装包通过xftp上传到/opt/software 安装部署Spark 1、解压spark-3.3…

2024年华为OD机试真题-多段线数据压缩-Java-OD统一考试(C卷)

题目描述: 下图中,每个方块代表一个像素,每个像素用其行号和列号表示。 为简化处理,多段线的走向只能是水平、竖直、斜向45度。 上图中的多段线可以用下面的坐标串表示:(2, 8), (3, 7), (3, 6), (3, 5), (4, 4), (5, 3), (6, 2), (7, 3), (8, 4), (7, 5)。 但可以发现,这…

Nginx与history路由模式:刷新页面404问题

使用nginx部署前端项目&#xff0c;路由模式采用history模式时&#xff0c;刷新页面之后&#xff0c;显示404。 路由模式 前端路由的基本作用为&#xff1a; ①当浏览器地址变化时&#xff0c;切换页面&#xff1b; ②点击浏览器后退、前进按钮时&#xff0c;更新网页内容&…

VUE基础知识(JAVA后端入门篇)

VUE基础知识&#xff08;JAVA后端入门篇&#xff09; Vue是一套前端框架&#xff0c;免除原生JavaScriptr中的DOM操作&#xff0c;简化书写基于MVVM(Model–View-ViewModel)思想&#xff0c;实现数据的双向绑定&#xff0c;将编程的关注点放在数据上Vue.js - 渐进式 JavaScrip…

嵌入式Qt 第一个Qt项目

一.创建Qt项目 打开Qt Creator 界面选择 New Project或者选择菜单栏 【文件】-【新建文件或项目】菜单项 弹出New Project对话框&#xff0c;选择Qt Widgets Application 选择【Choose】按钮&#xff0c;弹出如下对话框 设置项目名称和路径&#xff0c;按照向导进行下一步 选…

关于显卡、显卡驱动、cuda、cuDNN等的区别

关于显卡、显卡驱动、cuda、cuDNN等的区别 刚接触AI或机器学习框架时&#xff0c;经常会被这几个概念搞混&#xff0c;尤其是显卡驱动、cuda、cuDNN这个三个软的东西&#xff1b;此外&#xff0c;NVCC、cudatoolkit又是什么呢&#xff1f; 1. 显卡(GPU) 显卡就是硬件&#xff…

LeetCode、72. 编辑距离【中等,二维DP】

文章目录 前言LeetCode、72. 编辑距离【中等&#xff0c;二维DP】题目链接与分类二维DP 资料获取 前言 博主介绍&#xff1a;✌目前全网粉丝2W&#xff0c;csdn博客专家、Java领域优质创作者&#xff0c;博客之星、阿里云平台优质作者、专注于Java后端技术领域。 涵盖技术内容…

TinUI v5预发布记录

TinUI v5预发布记录 前言新控件滚动选择框菜单按钮 新样式pre1pre2pre3pre4 新功能导入字体文件释放子窗口 前言 TinUI是一个从2021年正式开始并一直维护到现在的小项目&#xff0c;中间经过了四代版本的更新。因为一些原因&#xff0c;2023年&#xff0c;TinUI-4后更新较少。…

几个经典金融理论

完整EA&#xff1a;Nerve Knife.ex4黄金交易策略_黄金趋势ea-CSDN博客 一、预期效用理论 预期效用理论是描述人们在做出决策时如何考虑风险和不确定性的一种理论。该理论最初由经济学家冯诺伊曼&#xff08;John von Neumann&#xff09;和奥斯卡摩根斯坦恩&#xff08;Oskar…

Rust基础拾遗--辅助功能

Rust基础拾遗 前言1.错误处理1.1 panic展开调用栈中止Result捕捉错误Result错误别名打印错误传播错误处理多种Error类型处理“不可能发生”的错误处理main() 中的错误声明自定义错误类型为什么是 Result 2. create与模块3. 宏4. 不安全代码5. 外部函数 前言 通过Rust程序设计-第…

Linux释放内存

free -m是Linux上查看内存的指令&#xff0c;其中-m是以兆&#xff08;MB&#xff09;为单位&#xff0c;如果不加则以KB为单位。 如下图表示&#xff0c;&#xff08;total&#xff09;总物理内存是809MB&#xff0c;&#xff08;used&#xff09;已使用167MB&#xff0c;&…

深度解析 Netty 架构与原理

一共 28661字&#xff0c;耐心看完。 在阅读本文前最好有 Java 的 IO 编程经验&#xff08;知道 Java 的各种 IO 流&#xff09;&#xff0c;以及 Java 网络编程经验&#xff08;用 ServerSocket 和 Socket 写过 demo&#xff09;&#xff0c;并对 Java NIO 有基本的认识&…