当前位置: 首页 > news >正文

Java 网络编程

1.UDP和TCP

UDP和TCP是传输层协议中最核心的两种协议

他们的特点分别是

UDP: 无连接,不可靠传输,面向数据报,全双工

TCP: 有连接,是可靠传输,面向字节流,全双工

有无连接

有连接:就好比两个人打电话,打电话的一方发出连接请求,被打电话的一方选择确认连接,此时双方才能进行通话

无连接:就好比QQ,微信发消息,发消息的一方不需要和另一方取得连接就可以发送消息

可靠传输

在网络通信中,是没办法保证100%传输成功的

不可靠传输:发送出去就不管了

可靠传输:发送方能知道信息是否传出去了

面向数据报/面向字节流

面向数据报:以数据报为单位进行接发

面向字节流:以字节为单位进行接发,类似于文件读写

全双工

一个通信通道,可以双向传输(既可以接收,也可以发送)

半双工:可以发也可以收,但是不可以同时进行

2.实现UDP版本的服务器和客户端

为方便,此处实现的服务器为回显服务器(服务器的响应和请求相同),TCP也是一样的

首先要认识几个类

2.1 DatagramSocket

使用此类,表示一个socket对象,有了一个socket对象就可以对另一台主机进行通信了

注意:在操作系统中,socket会当做文件来处理,会存放到文件描述符表中

构造方法:

1.DatagramSocket(int port)

里面传入一个端口号(1024~65535),可以确定端口

2.DatagramSocket()

操作系统会随机分配一个空闲的端口

方法:

void receive(DatagramPacket p)

用来接收数据报,此时要传入一个空的DatagramPacket对象,内容及数据会存放到DatagramPacket对象中

void send(DatagramPacket p)

用来发送数据报,数据要提前存放在DatagramPacket对象中

2.2 DatagramPacket

表示UDP中传输的一个报文,可以指定一些数据进去

构造方法:

DatagramPacket(byte[] buf,int length)

里面放一个byte数组作为缓冲区,length是要存放的长度

DatagramPacket(byte[] buf,int length,SocketAddress address)

和上面的相比,多了一个address参数,该参数可以传入IP和端口号

方法:

InetSddress getAddress()

获取IP地址

int getPort()

获取端口号

byte[] getData()

获取数据报中的数据

2.3 编写UDP版本的服务器

首先搭建好一个大体框架,并在构造方法中创建出一个DatagramSocket对象

注意:构造时要传入一个端口号,因为在网络通信中,服务器是被动方,如果端口号为随机,那么此时客户端就不知道服务器的端口号,也就无法进行通信了

public class UdpEchoServer {private DatagramSocket socket = null;public UdpEchoServer(int port) throws SocketException {socket = new DatagramSocket(port);}public void start() {}
}

然后在start中实现具体的服务器代码

首先是一个while(true)循环包含整个方法体,因为大多数服务器需要全天24h不断的去处理请求

之后大致分四步:

1.读取客户端发来的请求

            //receive 方法的参数是一个输出型参数,需要构建好一个空白的 DatagramPacket 对象,让receive去补充DatagramPacket requestPacket = new DatagramPacket(new byte[4096],4096);//如果客户端发来了请求,receive就能顺利读出来请求,如果没有请求就会进入阻塞socket.receive(requestPacket);//将数组中的数据转化为字符串,方便读取String request = new String(requestPacket.getData(),0,requestPacket.getLength());

2.根据请求,构建响应

    String response = process(request);

process方法为处理响应的方法(就是将请求直接返回去)

    public String process(String request) {return request;}

3.返回响应

//此处DatagramPacket 的参数就不能是空的数组了,因为要将响应的字符串返回去//send的参数也是DatagramPacket//在receive时,requestPacket中已经存放了 客户端的IP地址和端口号DatagramPacket responsePacket = new DatagramPacket(response.getBytes(),response.getBytes().length,requestPacket.getSocketAddress());socket.send(responsePacket);

4.打印信息(可有可无)

System.out.printf("[%s:%d] req: %s;resp : %s\n",requestPacket.getAddress().toString(),requestPacket.getPort(),request,response);

打印内容为(从左到右): 客户端的IP,客户端的端口号,请求,响应

整体代码如下:

public class UdpEchoServer {private DatagramSocket socket = null;public UdpEchoServer(int port) throws SocketException {socket = new DatagramSocket(port);}public void start() throws IOException {System.out.println("服务器启动");while(true) {//1. 读取客户端发来的请求DatagramPacket requestPacket = new DatagramPacket(new byte[4096],4096);socket.receive(requestPacket);String request = new String(requestPacket.getData(),0,requestPacket.getLength());//2. 根据请求制造响应String response = process(request);//3. 将响应写会到客户端DatagramPacket responsePacket = new DatagramPacket(response.getBytes(),response.getBytes().length,requestPacket.getSocketAddress());socket.send(responsePacket);//4. 打印这次请求响应的处理过程System.out.printf("[%s:%d] req: %s;resp : %s\n",requestPacket.getAddress().toString(),requestPacket.getPort(),request,response);}}//因为此处是回响服务器,所以响应和请求相同public String process(String request) {return request;}public static void main(String[] args) throws IOException {UdpEchoServer server = new UdpEchoServer(9090);server.start();}
}

2.4 编写UDP版本的客户端

构建框架,相比于服务器,客户端在构造方法处还需要传入服务器的端口号和IP

public class UdpEchoClient {private DatagramSocket socket = null;private String serverIP = null;private int serverPort = 0;public UdpEchoClient(String serverIP,int serverPort) throws SocketException {socket = new DatagramSocket();this.serverIP = serverIP;this.serverPort = serverPort;}public void start() {}
}

start中的具体实现

仍然是一个while循环包含方法体

循环内容大致分四步:

1.从控制台构建请求

            //该句在循环外,如果每次循环都去创建Scanner太耗效率了Scanner scanner = new Scanner(System.in);System.out.print(">");String request = scanner.next();//判断是否要退出if(request.equals("exit")) {System.out.println("goodbye");break;}

2.发送请求

            // 构造一个 DatagramPacket 对象 此时该对象的参数要传入客户端的 IP(serverIP) 和 端口(serverPort)// 此处的IP需要的是一个32的整数形式,需要使用 InetAddress.getByName 进行一个转换DatagramPacket requestPacket = new DatagramPacket(request.getBytes(),request.getBytes().length,InetAddress.getByName(serverIP),serverPort);socket.send(requestPacket);

3.接收响应

            DatagramPacket responsePacket = new DatagramPacket(new byte[4096],4096);socket.receive(responsePacket);String response = new String(responsePacket.getData(),0,responsePacket.getLength());

4.打印响应

            System.out.println(response);

整体代码如下:

public class UdpEchoClient {private DatagramSocket socket = null;private String serverIP = null;private int serverPort = 0;public UdpEchoClient(String serverIP,int serverPort) throws SocketException {socket = new DatagramSocket();this.serverIP = serverIP;this.serverPort = serverPort;}public void start() throws IOException {System.out.println("客户端启动");Scanner scanner = new Scanner(System.in);while(true) {//1.从控制台读取要发送的请求System.out.print(">");String request = scanner.next();if(request.equals("exit")) {System.out.println("goodbye");break;}//2.构造成一个UDP请求,并发送DatagramPacket requestPacket = new DatagramPacket(request.getBytes(),request.getBytes().length,InetAddress.getByName(serverIP),serverPort);socket.send(requestPacket);//3.读取UDP服务器的响应,并解析DatagramPacket responsePacket = new DatagramPacket(new byte[4096],4096);socket.receive(responsePacket);String response = new String(responsePacket.getData(),0,responsePacket.getLength());//4.把解析好的结果显示出来System.out.println(response);}}public static void main(String[] args) throws IOException {UdpEchoClient client = new UdpEchoClient("127.0.0.1",9090);client.start();}
}

3.实现TCP版本的服务器和客户端

3.1 ServerSocket

ServerSocket是专门给服务器(TCP)使用的socket对象

构造方法:

ServerSocket(int port)

构建一个socket并指定端口号

方法:

Socket accept()

开始监听指定端口,当有客户端绑定时,返回一个Socket对象并建立连接,否则,则进入阻塞等待

3.2 Socket

既会给客户端提供服务,也会给服务器提供服务(TCP)

构造方法:

Socket(String host,int port)

构造一个Socket对象,并与传入的端口号和IP进行连接

方法:

InputStream getInputStream()

返回一个与该Socket连接相关连的InputStream 对象

OutputStream getOutputStream()

返回一个与该Socket相关连的OutputStream 对象

3.3 编写TCP版本的服务器

首先是一个大体的框架,将ServerSocket对象打包好

public class TcpEchoServer {private ServerSocket serverSocket = null;public TcpEchoServer(int port) throws IOException {serverSocket = new ServerSocket(port);}public void start() {}//处理连接public void processConnection(Socket clientSocket) {}//处理请求public String process(String request) {return request;}
}

在连接的处理时,首先要连接上资源(InputStream 读,OutputStream 写)

然后将以下四个步骤循环执行

1.读取请求

2.根据请求构造响应

3.返回响应

4.打印请求和响应(可有可无)

由于分段解释比较杂乱,此处将整个处理连接过程的代码全部给出

//处理连接public void processConnection(Socket clientSocket) {//打印日志 -- 客户端的IP和端口号System.out.printf("[%s:%d] 客户端上线\n",clientSocket.getInetAddress().toString(),clientSocket.getPort());try(InputStream inputStream = clientSocket.getInputStream();OutputStream outputStream = clientSocket.getOutputStream()) {Scanner scanner = new Scanner(inputStream);while(true) {//1.读取请求if (!scanner.hasNext()) {//此时没有下一个数据(客户端关闭了连接)System.out.printf("[%s:%d] 客户端下线\n",clientSocket.getInetAddress().toString(),clientSocket.getPort());break;}String request = scanner.next();//2.根据请求构造响应String response = process(request);//3.返回响应//可以使用 OutputStream 将字符串转化为字节数组传入//也可以使用字符流 PrintWrite 来转换//将 OutputStream 对象放入 PrintWrite 的对象参数中 就可以通过 PrintWrite 来输出PrintWriter printWriter = new PrintWriter(outputStream);//此处将数据写入,使用println换行 方便对端接收解析printWriter.println(response);//flush 用来刷新缓冲区printWriter.flush();//4.打印请求和响应System.out.printf("[%s:%d] req:%s resp:%s\n",clientSocket.getInetAddress().toString(),clientSocket.getPort(),request,response);}} catch (IOException e) {throw new RuntimeException(e);} finally {try {//由于每一次客户端进行连接时都会创建一个 clientSocket 出来//而 Socket 属于文件 会占用文件描述符表clientSocket.close();} catch (IOException e) {e.printStackTrace();}}}

在start中也需要一个循环去不断接收客户端的连接请求(此处使用的是单线程模式,如果上一个客户端的请求没有处理完,是无法处理下一个的)

//单线程版本public void start() throws IOException {System.out.println("服务器启动");while(true) {//使用 clientSocket 来和客户端交流Socket clientSocket = serverSocket.accept();//使用该方法处理连接processConnection(clientSocket);}}

整体代码如下:

多线程版本和线程池版本的start一并放到下面的代码中

public class TcpEchoServer {private ServerSocket serverSocket = null;public TcpEchoServer(int port) throws IOException {serverSocket = new ServerSocket(port);}//线程池版本/*public void start() throws IOException {System.out.println("服务器启动");while(true) {//创建线程池ExecutorService threadPool = Executors.newCachedThreadPool();//使用 clientSocket 来和客户端交流Socket clientSocket = serverSocket.accept();threadPool.submit(new Runnable() {@Overridepublic void run() {processConnection(clientSocket);}});}}*///多线程版本/*public void start() throws IOException {System.out.println("服务器启动");while(true) {//使用 clientSocket 来和客户端交流Socket clientSocket = serverSocket.accept();//使用多线程来处理Thread t = new Thread(() -> {processConnection(clientSocket);});t.start();}}*///单线程版本public void start() throws IOException {System.out.println("服务器启动");while(true) {//使用 clientSocket 来和客户端交流Socket clientSocket = serverSocket.accept();//使用该方法处理连接processConnection(clientSocket);}}//处理连接public void processConnection(Socket clientSocket) {//打印日志 -- 客户端的IP和端口号System.out.printf("[%s:%d] 客户端上线\n",clientSocket.getInetAddress().toString(),clientSocket.getPort());try(InputStream inputStream = clientSocket.getInputStream();OutputStream outputStream = clientSocket.getOutputStream()) {Scanner scanner = new Scanner(inputStream);while(true) {//1.读取请求if (!scanner.hasNext()) {//此时没有下一个数据(客户端关闭了连接)System.out.printf("[%s:%d] 客户端下线\n",clientSocket.getInetAddress().toString(),clientSocket.getPort());break;}String request = scanner.next();//2.根据请求构造响应String response = process(request);//3.返回响应//可以使用 OutputStream 将字符串转化为字节数组传入//也可以使用字符流 PrintWrite 来转换//将 OutputStream 对象放入 PrintWrite 的对象参数中 就可以通过 PrintWrite 来输出PrintWriter printWriter = new PrintWriter(outputStream);//此处将数据写入,使用println换行 方便对端接收解析printWriter.println(response);//flush 用来刷新缓冲区printWriter.flush();//4.打印请求和响应System.out.printf("[%s:%d] req:%s resp:%s\n",clientSocket.getInetAddress().toString(),clientSocket.getPort(),request,response);}} catch (IOException e) {throw new RuntimeException(e);} finally {try {//由于每一次客户端进行连接时都会创建一个 clientSocket 出来//而 Socket 属于文件 会占用文件描述符表clientSocket.close();} catch (IOException e) {e.printStackTrace();}}}public String process(String request) {return request;}public static void main(String[] args) throws IOException {TcpEchoServer tcpEchoServer = new TcpEchoServer(9090);tcpEchoServer.start();}
}

3.4 编写TCP版本的客户端

首先是大体框架

public class TcpEchoClient {private Socket socket = null;public TcpEchoClient(String serverIP,int serverPort) throws IOException {//下面这个构造语句就会触发TCP建立连接//里面需要传服务器的IP和端口号socket = new Socket(serverIP,serverPort);}public void start() {}
}

start中实现请求的传输和获取响应

首先是资源的创建(InputStream 读,OutputStream 写)

然后套入循环执行

分为四步(大部分和服务器相似):

1.获取请求

2.发送请求

3.接收响应

4.打印响应(可有可无)

public void start() {System.out.println("客户端启动");try(InputStream inputStream = socket.getInputStream();OutputStream outputStream = socket.getOutputStream()) {while(true) {//1.从键盘获取用户请求Scanner scanner = new Scanner(System.in);System.out.print(">");String request = scanner.next();if(request.equals("exit")) {System.out.println("goodbye");break;}//2.发送请求到服务器PrintWriter printWriter = new PrintWriter(outputStream);printWriter.println(request);//刷新 确保数据发送了出去printWriter.flush();//3.接收服务器返回的响应Scanner respScanner = new Scanner(inputStream);String response = respScanner.next();//4.打印响应System.out.println(response);}} catch (IOException e) {e.printStackTrace();}}

整体代码如下:

public class TcpEchoClient {private Socket socket = null;public TcpEchoClient(String serverIP,int serverPort) throws IOException {//下面这个构造语句就会触发TCP建立连接//里面需要传服务器的IP和端口号socket = new Socket(serverIP,serverPort);}public void start() {System.out.println("客户端启动");try(InputStream inputStream = socket.getInputStream();OutputStream outputStream = socket.getOutputStream()) {while(true) {//1.从键盘获取用户请求Scanner scanner = new Scanner(System.in);System.out.print(">");String request = scanner.next();if(request.equals("exit")) {System.out.println("goodbye");break;}//2.发送请求到服务器PrintWriter printWriter = new PrintWriter(outputStream);printWriter.println(request);//刷新 确保数据发送了出去printWriter.flush();//3.接收服务器返回的响应Scanner respScanner = new Scanner(inputStream);String response = respScanner.next();//4.打印响应System.out.println(response);}} catch (IOException e) {e.printStackTrace();}}public static void main(String[] args) throws IOException {TcpEchoClient tcpEchoClient = new TcpEchoClient("127.0.0.1",9090);tcpEchoClient.start();}
}

相关文章:

Java 网络编程

1.UDP和TCPUDP和TCP是传输层协议中最核心的两种协议他们的特点分别是UDP: 无连接,不可靠传输,面向数据报,全双工TCP: 有连接,是可靠传输,面向字节流,全双工有无连接有连接:就好比两个人打电话,打电话的一方发出连接请求,被打电话的一方选择确认连接,此时双方才能进行通话无连接…...

BEV学习记录

近期可能要经常性的开展BEV工作,打算把自己觉着不错的网站拿出来记录一下。 首先贴上来我还没有细读的一篇觉着不错的文章。 自动驾驶感知新范式——BEV感知经典论文总结和对比(上)_苹果姐的博客-CSDN博客_bev视角 开山之作--LSS ECCV 202…...

Webrtc Native C++切换音频输入源

modules/audio_device/audio_device_impl.cc #include “api/audio_options.h” #include “modules/audio_device/include/factory.h” // 创建一个 AudioDeviceModule 对象 auto audio_device_module = webrtc::AudioDeviceModule::Create( webrtc::AudioDeviceModule::kPl…...

裸辞5个月,面试了37家公司,终于找到理想工作了

上半年裁员,下半年裸辞,有不少人高呼裸辞后躺平真的好快乐!但也有很多人,裸辞后的生活五味杂陈。 面试37次终于找到心仪工作 因为工作压力大、领导PUA等各种原因,今年2月下旬我从一家互联网小厂裸辞,没想…...

Mybatis-plus@DS实现动态切换数据源应用

目录1 DS实现动态切换数据源原理2 不可在事务中切换数据库分析解决3 原因解析1 DS实现动态切换数据源原理 首先mybatis-plus使用com.baomidou.dynamic.datasource.AbstractRoutingDataSource继承 AbstractDataSource接管数据源;具体实现类为com.baomidou.dynamic.d…...

SpringBoot的创建和使用

SpringBoot是什么?SpringBoot诞生的目的就是为了简化Spring开发,而相对于Spring,SpringBoot算是一个很大的升级,就如同汽车手动挡变成了自动挡。Spring:SpringBoot:SpringBoot的优点SpringBoot让Spring开发…...

居家电话客服宝典

客服分类从销售的流程来分,客服分为售前和售后。售前一般都带有销售性质,工资主要靠提成,售后一般是解答问题,工资主要看服务质量和差评量。从工作模式来分,客服分为在线客服和热线客服。在线客服以打字聊天为主&#…...

开发方案设计

1、开发流程产品需求设计-->需求粗评-->做设计方案-->粗估时-->需求细评-->排期-->开发-->提测、修bug-->code review-->上线设计方案主要是写实现思路、模块划分code review:完善代码,发现未考虑到的边界问题2、具体实现方案…...

文件路径模块pathlib

文件路径模块pathlib 文章目录文件路径模块pathlib1.概述2.创建路径2.1.创建非windos平台路径2.2.动态拼接路径joinpath2.3.替换文件名称 with_name2.4.创建固定目录2.5.创建文件夹和文件1.创建多级目录mkdir2.创建空文件3.路径解析3.1.根据路径分隔符解析路径parts3.2.获取父级…...

spring cloud篇——什么是服务熔断?服务降级?服务限流?spring cloud有什么优势?

文章目录一、spring cloud 有什么优势二、服务熔断2.1、雪崩效应2.2、DubboHystrixCommand三、服务降级四、服务限流4.1、限流算法4.2、应用级限流4.3、池化技术4.4、分布式限流4.5、基于Redis 功能的实现限流4.6、基于令牌桶算法的实现4.6.1 、Java实现一、spring cloud 有什么…...

Tomcat构建

软件架构C/S:Client/Server.需要安装才能使用。B/S:Brower/Server。有浏览器就可以。资源分类动态资源:每个用户访问相同的资源后,得到的结果可能不一样,称为动态资源。动态资源被访问后,先转换为静态资源,再被浏览器解…...

入门深度学习——基于全连接神经网络的手写数字识别案例(python代码实现)

入门深度学习——基于全连接神经网络的手写数字识别案例(python代码实现) 一、网络构建 1.1 问题导入 如图所示,数字五的图片作为输入,layer01层为输入层,layer02层为隐藏层,找出每列最大值对应索引为输…...

预算砍砍砍,IT运维如何降本增效

疫情短暂过去,一个乐观的共识正在蔓延:2023年的互联网,绝对不会比2022年更差。 “降本”是过去一年许多公司的核心策略,营销大幅缩水、亏损业务大量撤裁,以及层出不穷的裁员消息。而2023年在可预期的经济复苏下&#…...

10.Jenkins用tags的方式自动发布java应用

Jenkins用tags的方式自动发布java应用1.配置jenkins,告诉jenkins,jdk的安装目录,maven的安装目录2.构建一个maven项目指定构建参数,选择Git Paramete在源码管理中,填写我们git项目的地址,调用变量构建前执行…...

2023新华为OD机试题 - 相同数字的积木游戏 1(JavaScript)

相同数字的积木游戏 1 题目 小华和小薇一起通过玩积木游戏学习数学。 他们有很多积木,每个积木块上都有一个数字, 积木块上的数字可能相同。 小华随机拿一些积木挨着排成一排,请小薇找到这排积木中数字相同且所处位置最远的 2 块积木块,计算他们的距离。 小薇请你帮忙替她…...

重构之改善既有代码的设计(一)

1.1 何为重构,为何重构 第一个定义是名词形式: 重构(名词):对软件内部结构的一种调整,目的是在不改变「软件可察行为」前提下,提高其可理解性,降低修改成本。 「重构」的另一个用…...

Kotlin data class 数据类用法

实验数据 {"code":1,"message":"成功","data":{"name":"周杰轮","gender":1} }kotlin数据类使用方便提供如下内部Api: equals()/hashCode()对 toString() componentN()按声明顺序与属性相…...

随笔-老子不想牺牲了

18年来到这个项目组,当时只有8个人,包括经常不在的架构师和经理。当时的工位在西区1栋A座,办公桌很宽敞。随着项目的发展,入职的人越来越多,项目的工位也是几经搬迁。基本上每次搬迁时,我的工位都是挑剩下的…...

三种查找Windows10环境变量的方法

文章目录一.在设置中查看二. 在我的电脑中查看三. 在资源管理器里查看一.在设置中查看 在系统中搜索设置 打开设置,在设置功能里,点击第一项 系统 在系统功能里,左侧菜单找到关于 在关于的相关设置里可以看到高级系统设置 点击高级系…...

STM32单片机DS18B20测温程序源代码

OLED液晶屏电路接口DS18B20电路接口STM32单片机DS18B20测温程序源代码#include "sys.h"#define LED_RED PBout(12)#define LED_GREEN PBout(13)#define LED_YELLOW PBout(14)#define LED_BLUE PBout(15)#define DS18B20_IO_IN() {GPIOA->CRL&0XFFFFFFF0;GPIOA…...

Unity3D中Gfx.WaitForPresent优化方案

前言 在Unity中,Gfx.WaitForPresent占用CPU过高通常表示主线程在等待GPU完成渲染(即CPU被阻塞),这表明存在GPU瓶颈或垂直同步/帧率设置问题。以下是系统的优化方案: 对惹,这里有一个游戏开发交流小组&…...

深入浅出:JavaScript 中的 `window.crypto.getRandomValues()` 方法

深入浅出:JavaScript 中的 window.crypto.getRandomValues() 方法 在现代 Web 开发中,随机数的生成看似简单,却隐藏着许多玄机。无论是生成密码、加密密钥,还是创建安全令牌,随机数的质量直接关系到系统的安全性。Jav…...

基于服务器使用 apt 安装、配置 Nginx

🧾 一、查看可安装的 Nginx 版本 首先,你可以运行以下命令查看可用版本: apt-cache madison nginx-core输出示例: nginx-core | 1.18.0-6ubuntu14.6 | http://archive.ubuntu.com/ubuntu focal-updates/main amd64 Packages ng…...

Maven 概述、安装、配置、仓库、私服详解

目录 1、Maven 概述 1.1 Maven 的定义 1.2 Maven 解决的问题 1.3 Maven 的核心特性与优势 2、Maven 安装 2.1 下载 Maven 2.2 安装配置 Maven 2.3 测试安装 2.4 修改 Maven 本地仓库的默认路径 3、Maven 配置 3.1 配置本地仓库 3.2 配置 JDK 3.3 IDEA 配置本地 Ma…...

大语言模型(LLM)中的KV缓存压缩与动态稀疏注意力机制设计

随着大语言模型(LLM)参数规模的增长,推理阶段的内存占用和计算复杂度成为核心挑战。传统注意力机制的计算复杂度随序列长度呈二次方增长,而KV缓存的内存消耗可能高达数十GB(例如Llama2-7B处理100K token时需50GB内存&a…...

Spring是如何解决Bean的循环依赖:三级缓存机制

1、什么是 Bean 的循环依赖 在 Spring框架中,Bean 的循环依赖是指多个 Bean 之间‌互相持有对方引用‌,形成闭环依赖关系的现象。 多个 Bean 的依赖关系构成环形链路,例如: 双向依赖:Bean A 依赖 Bean B,同时 Bean B 也依赖 Bean A(A↔B)。链条循环: Bean A → Bean…...

技术栈RabbitMq的介绍和使用

目录 1. 什么是消息队列?2. 消息队列的优点3. RabbitMQ 消息队列概述4. RabbitMQ 安装5. Exchange 四种类型5.1 direct 精准匹配5.2 fanout 广播5.3 topic 正则匹配 6. RabbitMQ 队列模式6.1 简单队列模式6.2 工作队列模式6.3 发布/订阅模式6.4 路由模式6.5 主题模式…...

从物理机到云原生:全面解析计算虚拟化技术的演进与应用

前言:我的虚拟化技术探索之旅 我最早接触"虚拟机"的概念是从Java开始的——JVM(Java Virtual Machine)让"一次编写,到处运行"成为可能。这个软件层面的虚拟化让我着迷,但直到后来接触VMware和Doc…...

[USACO23FEB] Bakery S

题目描述 Bessie 开了一家面包店! 在她的面包店里,Bessie 有一个烤箱,可以在 t C t_C tC​ 的时间内生产一块饼干或在 t M t_M tM​ 单位时间内生产一块松糕。 ( 1 ≤ t C , t M ≤ 10 9 ) (1 \le t_C,t_M \le 10^9) (1≤tC​,tM​≤109)。由于空间…...

webpack面试题

面试题:webpack介绍和简单使用 一、webpack(模块化打包工具)1. webpack是把项目当作一个整体,通过给定的一个主文件,webpack将从这个主文件开始找到你项目当中的所有依赖文件,使用loaders来处理它们&#x…...