【Netty】Netty 程序引导类(九)
文章目录
- 前言
- 一、引导程序类
- 二、AbstractBootStrap 抽象类
- 三、Bootstrap 类
- 四、ServerBootstrap 类
- 五、引导服务器
- 5.1、 实例化引导程序类
- 5.2、设置 EventLoopGroup
- 5.3、指定 Channel 类型
- 5.4、指定 ChannelHandler
- 5.5、设置 Channel 选项
- 5.6、绑定端口启动服务
- 六、引导客户端
- 6.1、实例化引导程序类
- 6.2、设置 EventLoopGroup
- 6.3、指定 Channel 类型
- 6.4、设置 Channel 选项
- 6.5、指定 ChannelHandler
- 6.6、连接到服务器
- 总结
前言
回顾Netty系列文章:
- Netty 概述(一)
- Netty 架构设计(二)
- Netty Channel 概述(三)
- Netty ChannelHandler(四)
- ChannelPipeline源码分析(五)
- 字节缓冲区 ByteBuf (六)(上)
- 字节缓冲区 ByteBuf(七)(下)
- Netty 如何实现零拷贝(八)
程序引导类(Bootstrap)可以理解为是一个程序的入口程序,在 Java 程序中,就是一个包含 main 方法的程序类。在 Netty 中,引导程序还包含一系列的配置项。本篇文章我们就来介绍 Netty 的引导程序。
一、引导程序类
引导程序类是一种引导程序,使 Netty 程序可以很容易地引导一个 Channel。在 Netty 中,承担引导程序的是 AbstractBootStrap抽象类。
引导程序类都在io.netty.bootstrap包下。AbstractBootStrap抽象类有两个子类:Bootstrap和ServerBootstrap,分别用于引导客户端程序及服务的程序。
下图展示了引导程序类的关系:

从上图可以看出,AbstractBootStrap抽象类实现了Cloneable接口。那么为什么需要实现Cloneable接口呢?
二、AbstractBootStrap 抽象类
在 Netty 中经常需要创建多个具有类似配置或者完全相同配置的Channel。为了支持这种模式而又不避免为每个Channel都创建并配置一个新的引导类实例,因此AbstractBootStrap被标记为了Cloneable。在一个已经配置完成的引导实例上调用clone()方法将返回另一个可以立即使用的引导类实例。
这种方式只会创建引导类实例的EventLoopGroup的一个浅拷贝,所以,EventLoopGroup将在所有克隆的Channel实例之间共享。这是可以接受的,毕竟这些克隆的Channel的生命周期都很短暂,例如,一个典型的场景是创建一个Channel以进行一次HTTP请求。
以下是AbstractBootStrap的核心源码:
public abstract class AbstractBootstrap<B extends AbstractBootstrap<B, C>, C extends Channel> implements Cloneable {volatile EventLoopGroup group;private volatile ChannelFactory<? extends C> channelFactory;private volatile SocketAddress localAddress;private final Map<ChannelOption<?>, Object> options = new LinkedHashMap();private final Map<AttributeKey<?>, Object> attrs = new ConcurrentHashMap();private volatile ChannelHandler handler;AbstractBootstrap() {//禁止从其他程序包扩展}AbstractBootstrap(AbstractBootstrap<B, C> bootstrap) {this.group = bootstrap.group;this.channelFactory = bootstrap.channelFactory;this.handler = bootstrap.handler;this.localAddress = bootstrap.localAddress;synchronized(bootstrap.options) {this.options.putAll(bootstrap.options);}this.attrs.putAll(bootstrap.attrs);}//...
}
从上述源码可以看出,子类型B是其父类型的一个类型参数,因此可以返回到运行时实例的引用以支持方法的链式调用。从私有变量可以看出,AbstractBootStrap所要管理的启动配置包括EventLoopGroup、SocketAddress、Channel配置、ChannelHandler等信息。
AbstractBootStrap是禁止被除io.netty.bootstrap包外其他程序所扩展的,因此可以看到AbstractBootStrap默认构造方法被设置为了包内可见。
三、Bootstrap 类
BootStrap 类是AbstractBootStrap抽象类的子类之一,主要是用于客户端或者使用了无连接协议的应用程序。
以下是BootStrap 类的核心源码:
public class Bootstrap extends AbstractBootstrap<Bootstrap, Channel> {private static final InternalLogger logger = InternalLoggerFactory.getInstance(Bootstrap.class);private static final AddressResolverGroup<?> DEFAULT_RESOLVER;private final BootstrapConfig config = new BootstrapConfig(this);private volatile AddressResolverGroup<SocketAddress> resolver;private volatile SocketAddress remoteAddress;public Bootstrap() {this.resolver = DEFAULT_RESOLVER;}private Bootstrap(Bootstrap bootstrap) {super(bootstrap);this.resolver = DEFAULT_RESOLVER;this.resolver = bootstrap.resolver;this.remoteAddress = bootstrap.remoteAddress;}public Bootstrap resolver(AddressResolverGroup<?> resolver) {this.resolver = resolver == null ? DEFAULT_RESOLVER : resolver;return this;}public Bootstrap remoteAddress(SocketAddress remoteAddress) {this.remoteAddress = remoteAddress;return this;}public Bootstrap remoteAddress(String inetHost, int inetPort) {this.remoteAddress = InetSocketAddress.createUnresolved(inetHost, inetPort);return this;}public Bootstrap remoteAddress(InetAddress inetHost, int inetPort) {this.remoteAddress = new InetSocketAddress(inetHost, inetPort);return this;}public ChannelFuture connect() {this.validate();SocketAddress remoteAddress = this.remoteAddress;if (remoteAddress == null) {throw new IllegalStateException("remoteAddress not set");} else {return this.doResolveAndConnect(remoteAddress, this.config.localAddress());}}public ChannelFuture connect(String inetHost, int inetPort) {return this.connect(InetSocketAddress.createUnresolved(inetHost, inetPort));}public ChannelFuture connect(InetAddress inetHost, int inetPort) {return this.connect(new InetSocketAddress(inetHost, inetPort));}public ChannelFuture connect(SocketAddress remoteAddress) {ObjectUtil.checkNotNull(remoteAddress, "remoteAddress");this.validate();return this.doResolveAndConnect(remoteAddress, this.config.localAddress());}public ChannelFuture connect(SocketAddress remoteAddress, SocketAddress localAddress) {ObjectUtil.checkNotNull(remoteAddress, "remoteAddress");this.validate();return this.doResolveAndConnect(remoteAddress, localAddress);}//...public Bootstrap validate() {super.validate();if (this.config.handler() == null) {throw new IllegalStateException("handler not set");} else {return this;}}public Bootstrap clone() {return new Bootstrap(this);}public Bootstrap clone(EventLoopGroup group) {Bootstrap bs = new Bootstrap(this);bs.group = group;return bs;}public final BootstrapConfig config() {return this.config;}final SocketAddress remoteAddress() {return this.remoteAddress;}final AddressResolverGroup<?> resolver() {return this.resolver;}...
}
上述方法主要分为以下几类:
- group:设置用于处理Channel所有事件的EventLoopGroup。
- channel:指定了 Channel的实现类。
- localAddress:指定 Channel应该绑定到的本地地址。如果没有指定,则有操作系统创建一个随机的地址。或者,也可以通过bind()或者connect()方法指定localAddress。
- option:设置ChannelOption,其将被应用到每个新创建的Channel的ChannelConfig。这些选项将会通过bind()或者connect()方法设置到Channel,配置的顺序与调用先后没有关系。这个方法在Channel已经被创建后再次调用就不会再起任何效果了。支持什么样的ChannelOption取决于所使用的Channel类型。
- attr:指定新创建的Channel的属性值。这些属性值是通过bind()或者connect()方法设置到Channel。配置的顺序取决于调用的先后顺序。这个方法在Channel已经被创建后再次调用就不会再起任何效果了。
- handler:设置被添加到ChannelPipeline以接收事件通知的ChannelHandler。
- remoteAddress:设置远程地址。也可以通过connect()方法来指定它。
clone:创建一个当前Bootstrap的克隆,其具有和原始的Bootstrap相同的设置信息。 - connect:用于连接到远程节点并返回一个ChannelFuture,并将会在连接操作完成后接收到通知。
- bind:绑定Channel并返回一个ChannelFuture,其将会在绑定操作完成之后接收到通知,在那之后必须调用Channel。
BootStrap类中许多方法都继承自AbstractBootstrap类。
四、ServerBootstrap 类
ServerBootstrap 类是AbstractBootStrap抽象类的子类之一,主要是用于引导服务器程序。
以下是 ServerBootstrap 类的源码:
public class ServerBootstrap extends AbstractBootstrap<ServerBootstrap, ServerChannel> {private static final InternalLogger logger = InternalLoggerFactory.getInstance(ServerBootstrap.class);private final Map<ChannelOption<?>, Object> childOptions = new LinkedHashMap();private final Map<AttributeKey<?>, Object> childAttrs = new ConcurrentHashMap();private final ServerBootstrapConfig config = new ServerBootstrapConfig(this);private volatile EventLoopGroup childGroup;private volatile ChannelHandler childHandler;public ServerBootstrap() {}private ServerBootstrap(ServerBootstrap bootstrap) {super(bootstrap);this.childGroup = bootstrap.childGroup;this.childHandler = bootstrap.childHandler;synchronized(bootstrap.childOptions) {this.childOptions.putAll(bootstrap.childOptions);}this.childAttrs.putAll(bootstrap.childAttrs);}public ServerBootstrap group(EventLoopGroup group) {return this.group(group, group);}public ServerBootstrap group(EventLoopGroup parentGroup, EventLoopGroup childGroup) {super.group(parentGroup);if (this.childGroup != null) {throw new IllegalStateException("childGroup set already");} else {this.childGroup = (EventLoopGroup)ObjectUtil.checkNotNull(childGroup, "childGroup");return this;}}public <T> ServerBootstrap childOption(ChannelOption<T> childOption, T value) {ObjectUtil.checkNotNull(childOption, "childOption");synchronized(this.childOptions) {if (value == null) {this.childOptions.remove(childOption);} else {this.childOptions.put(childOption, value);}return this;}}public <T> ServerBootstrap childAttr(AttributeKey<T> childKey, T value) {ObjectUtil.checkNotNull(childKey, "childKey");if (value == null) {this.childAttrs.remove(childKey);} else {this.childAttrs.put(childKey, value);}return this;}public ServerBootstrap childHandler(ChannelHandler childHandler) {this.childHandler = (ChannelHandler)ObjectUtil.checkNotNull(childHandler, "childHandler");return this;}//...public ServerBootstrap clone() {return new ServerBootstrap(this);}/** @deprecated */@Deprecatedpublic EventLoopGroup childGroup() {return this.childGroup;}final ChannelHandler childHandler() {return this.childHandler;}final Map<ChannelOption<?>, Object> childOptions() {synchronized(this.childOptions) {return copiedMap(this.childOptions);}}final Map<AttributeKey<?>, Object> childAttrs() {return copiedMap(this.childAttrs);}public final ServerBootstrapConfig config() {return this.config;}//...
}
上述方法主要分为以下几类:
- group:设置ServerBootstrap要用的EventLoopGroup。这个EventLoopGroup将用于ServerChannel和被接受的子Channel的 I/O 处理。
- channel:设置将要被实例化的ServerChannel类。
- localAddress:指定 ServerChannel应该绑定到的本地地址。如果没有指定,则有操作系统创建一个随机的地址。或者,也可以通过bind()方法指定localAddress。
- option:指定要应用到新创建的ServerChannel的ChannelConfig的ChannelOption。这些选项将会通过bind()设置到Channel,在bind()方法被调用之后,设置或者改变ChannelOption将不会有任何效果。支持什么样的ChannelOption取决于所使用的Channel类型。
- childOption:指定当子Channel被接受时,应用到子Channel的ChannelConfig的ChannelOption。所支持的ChannelOption取决于所使用的Channel类型。
- attr:指定ServerChannel上的属性值。这些属性值是通过bind()或者connect()方法设置到Channel。在bind()方法被调用之后它们将不会有任何效果。
- childAttr:将属性设置给已经被接受的子Channel。之后再次调用将不会有任何效果。
- handler:设置被添加到ServerChannel的ChannelPipeline中的ChannelHandler。
- childHandler:设置将被添加到已被接受的子Channel的ChannelPipeline中的ChannelHandler。
- clone:克隆一个设置好原始的ServerBootstrap相同的ServerBootstrap。
- bind:绑定ServerChannel并返回一个ChannelFuture,其将会在绑定操作完成之后接收到通知(带着成功或者失败的结果)。
ServerBootstrap类中许多方法都继承自AbstractBootstrap类。
五、引导服务器
为了能更好的理解引导程序,下面就以 Echo 协议的服务器的代码为例。核心代码如下:
// 多线程事件循环器
EventLoopGroup bossGroup = new NioEventLoopGroup(); // boss
EventLoopGroup workerGroup = new NioEventLoopGroup(); // workertry {// 启动NIO服务的引导程序类ServerBootstrap b = new ServerBootstrap(); b.group(bossGroup, workerGroup) // 设置EventLoopGroup.channel(NioServerSocketChannel.class) // 指明新的Channel的类型.childHandler(new EchoServerHandler()) // 指定ChannelHandler.option(ChannelOption.SO_BACKLOG, 128) // 设置的ServerChannel的一些选项.childOption(ChannelOption.SO_KEEPALIVE, true); // 设置的ServerChannel的子Channel的选项// 绑定端口,开始接收进来的连接ChannelFuture f = b.bind(port).sync(); System.out.println("EchoServer已启动,端口:" + port);// 等待服务器 socket 关闭 。// 在这个例子中,这不会发生,但你可以优雅地关闭你的服务器。f.channel().closeFuture().sync();
} finally {// 优雅的关闭workerGroup.shutdownGracefully();bossGroup.shutdownGracefully();
}
引导 Netty 服务器主要分为几下几个步骤。
5.1、 实例化引导程序类
在上述代码中,首先是需要实例化引导程序类。由于是服务器端的程序,所以,实例化了一个ServerBootstrap。
5.2、设置 EventLoopGroup
设置ServerBootstrap的EventLoopGroup。上述服务器使用了两个NioEventLoopGroup,一个代表boss线程组,一个代表work线程组。
boss线程主要是接收客户端的请求,并将请求转发给work线程处理。
boss线程是轻量的,不会处理耗时的任务,因此可以承受高并发的请求。而真实的 I/O 操作都是由work线程在执行。
NioEventLoopGroup是支持多线程的,因此可以执行线程池的大小。如果没有指定,则 Netty 会指定一个默认的线程池大小,核心代码如下:
private static final int DEFAULT_EVENT_LOOP_THREADS;static {// 默认 EventLoopGroup 的线程数DEFAULT_EVENT_LOOP_THREADS = Math.max(1, SystemPropertyUtil.getInt("io.netty.eventLoopThreads", NettyRuntime.availableProcessors() * 2));if (logger.isDebugEnabled()) {logger.debug("-Dio.netty.eventLoopThreads: {}", DEFAULT_EVENT_LOOP_THREADS);}}public NioEventLoopGroup() {// 如果不指定, nThreads = 0this(0);}/*** @see MultithreadEventExecutorGroup#MultithreadEventExecutorGroup(int, Executor, Object...)*/protected MultithreadEventLoopGroup(int nThreads, Executor executor, Object... args) {// 如果不指定(nThreads = 0),默认值是 DEFAULT_EVENT_LOOP_THREADSsuper(nThreads == 0 ? DEFAULT_EVENT_LOOP_THREADS : nThreads, executor, args);}
从上述源码可以看出,如果NioEventLoopGroup实例化时,没有指定线程数,则最终默认值是DEFAULT_EVENT_LOOP_THREADS,而默认值DEFAULT_EVENT_LOOP_THREADS是根据当前机子的CPU 处理的个数乘以 2 得出的。
5.3、指定 Channel 类型
channel()方法用于指定ServerBootstrap的Channel类型。在本例中,使用的是NioServerSocketChannel类型,代表了服务器是一个基于ServerSocketChannel的实现,使用基于 NIO 选择器的实现来接受新连接。
5.4、指定 ChannelHandler
childHandler用于指定ChannelHandler,以便处理Channel的请求。上述例子中,指定的是自定义的EchoServerHandler。
5.5、设置 Channel 选项
option和childOption方法,分别用于设置ServerChannel及ServerChannel的子Channel的选项。这些选项定义在ChannelOption类中,包含以下常量:
public class ChannelOption<T> extends AbstractConstant<ChannelOption<T>> {public static final ChannelOption<ByteBufAllocator> ALLOCATOR = valueOf("ALLOCATOR");public static final ChannelOption<RecvByteBufAllocator> RCVBUF_ALLOCATOR = valueOf("RCVBUF_ALLOCATOR");public static final ChannelOption<MessageSizeEstimator> MESSAGE_SIZE_ESTIMATOR = valueOf("MESSAGE_SIZE_ESTIMATOR");public static final ChannelOption<Integer> CONNECT_TIMEOUT_MILLIS = valueOf("CONNECT_TIMEOUT_MILLIS");/*** @deprecated Use {@link MaxMessagesRecvByteBufAllocator}* and {@link MaxMessagesRecvByteBufAllocator#maxMessagesPerRead(int)}.*/@Deprecatedpublic static final ChannelOption<Integer> MAX_MESSAGES_PER_READ = valueOf("MAX_MESSAGES_PER_READ");public static final ChannelOption<Integer> WRITE_SPIN_COUNT = valueOf("WRITE_SPIN_COUNT");/*** @deprecated Use {@link #WRITE_BUFFER_WATER_MARK}*/@Deprecatedpublic static final ChannelOption<Integer> WRITE_BUFFER_HIGH_WATER_MARK = valueOf("WRITE_BUFFER_HIGH_WATER_MARK");/*** @deprecated Use {@link #WRITE_BUFFER_WATER_MARK}*/@Deprecatedpublic static final ChannelOption<Integer> WRITE_BUFFER_LOW_WATER_MARK = valueOf("WRITE_BUFFER_LOW_WATER_MARK");public static final ChannelOption<WriteBufferWaterMark> WRITE_BUFFER_WATER_MARK =valueOf("WRITE_BUFFER_WATER_MARK");public static final ChannelOption<Boolean> ALLOW_HALF_CLOSURE = valueOf("ALLOW_HALF_CLOSURE");public static final ChannelOption<Boolean> AUTO_READ = valueOf("AUTO_READ");/*** If {@code true} then the {@link Channel} is closed automatically and immediately on write failure.* The default value is {@code true}.*/public static final ChannelOption<Boolean> AUTO_CLOSE = valueOf("AUTO_CLOSE");public static final ChannelOption<Boolean> SO_BROADCAST = valueOf("SO_BROADCAST");public static final ChannelOption<Boolean> SO_KEEPALIVE = valueOf("SO_KEEPALIVE");public static final ChannelOption<Integer> SO_SNDBUF = valueOf("SO_SNDBUF");public static final ChannelOption<Integer> SO_RCVBUF = valueOf("SO_RCVBUF");public static final ChannelOption<Boolean> SO_REUSEADDR = valueOf("SO_REUSEADDR");public static final ChannelOption<Integer> SO_LINGER = valueOf("SO_LINGER");public static final ChannelOption<Integer> SO_BACKLOG = valueOf("SO_BACKLOG");public static final ChannelOption<Integer> SO_TIMEOUT = valueOf("SO_TIMEOUT");public static final ChannelOption<Integer> IP_TOS = valueOf("IP_TOS");public static final ChannelOption<InetAddress> IP_MULTICAST_ADDR = valueOf("IP_MULTICAST_ADDR");public static final ChannelOption<NetworkInterface> IP_MULTICAST_IF = valueOf("IP_MULTICAST_IF");public static final ChannelOption<Integer> IP_MULTICAST_TTL = valueOf("IP_MULTICAST_TTL");public static final ChannelOption<Boolean> IP_MULTICAST_LOOP_DISABLED = valueOf("IP_MULTICAST_LOOP_DISABLED");public static final ChannelOption<Boolean> TCP_NODELAY = valueOf("TCP_NODELAY");@Deprecatedpublic static final ChannelOption<Boolean> DATAGRAM_CHANNEL_ACTIVE_ON_REGISTRATION =valueOf("DATAGRAM_CHANNEL_ACTIVE_ON_REGISTRATION");public static final ChannelOption<Boolean> SINGLE_EVENTEXECUTOR_PER_GROUP =valueOf("SINGLE_EVENTEXECUTOR_PER_GROUP");}
5.6、绑定端口启动服务
bind()方法用于绑定端口,会创建一个Channel而后启动服务。
绑定成功后,返回一个ChannelFuture,以代表是一个异步的操作。在上述的例子里,使用的是sync()方法,以同步的方式来获取服务启动的结果。
六、引导客户端
为了能更好的理解引导程序,下面就以 Echo 协议的客户端的代码为例。核心代码如下:
// 配置客户端
EventLoopGroup group = new NioEventLoopGroup();
try {Bootstrap b = new Bootstrap();b.group(group).channel(NioSocketChannel.class).option(ChannelOption.TCP_NODELAY, true).handler(new EchoClientHandler());// 连接到服务器ChannelFuture f = b.connect(hostName, portNumber).sync();Channel channel = f.channel();ByteBuffer writeBuffer = ByteBuffer.allocate(32);try (BufferedReader stdIn = new BufferedReader(new InputStreamReader(System.in))) {String userInput;while ((userInput = stdIn.readLine()) != null) {writeBuffer.put(userInput.getBytes());writeBuffer.flip();writeBuffer.rewind();// 转为ByteBufByteBuf buf = Unpooled.copiedBuffer(writeBuffer);// 写消息到管道channel.writeAndFlush(buf);// 清理缓冲区writeBuffer.clear();}} catch (UnknownHostException e) {System.err.println("不明主机,主机名为: " + hostName);System.exit(1);} catch (IOException e) {System.err.println("不能从主机中获取I/O,主机名为:" + hostName);System.exit(1);}
} finally {// 优雅的关闭group.shutdownGracefully();
}
引导 Netty 客户端主要分为几下几个步骤。
6.1、实例化引导程序类
在上述代码中,首先是需要实例化引导程序类。由于是客户端的程序,所以,实例化了一个Bootstrap。
6.2、设置 EventLoopGroup
设置Bootstrap的EventLoopGroup。不同于服务器,客户端只需要使用了一个NioEventLoopGroup。
6.3、指定 Channel 类型
channel()方法用于指定Bootstrap的Channel类型。在本例中,由于是客户端使用,使用的是NioSocketChannel类型,代表了客户端是一个基于SocketChannel的实现,使用基于 NIO 选择器的实现来发起连接请求。
6.4、设置 Channel 选项
option用于设置Channel的选项。这些选项定义在ChannelOption类中。
6.5、指定 ChannelHandler
Handler用于设置处理服务端请求的ChannelHandler。上述例子中,指定的是自定义的EchoClientHandler。
6.6、连接到服务器
connect()方法用于连接到指定的服务器的Channel。
连接成功后,返回一个ChannelFuture,以代表是一个异步的操作。在上述的例子里,使用的是sync()方法,以同步的方式来获取服务启动的结果。
总结
通过上述对引导程序类的介绍,相信大家对于服务端和客户端的引导程序以及一些配置项的都有了一定的了解。通过看源码,我们就能更加清楚的知道 Netty 服务端和客户端的启动的过程。下节我们来分析Netty的线程模型。
相关文章:
【Netty】Netty 程序引导类(九)
文章目录 前言一、引导程序类二、AbstractBootStrap 抽象类三、Bootstrap 类四、ServerBootstrap 类五、引导服务器5.1、 实例化引导程序类5.2、设置 EventLoopGroup5.3、指定 Channel 类型5.4、指定 ChannelHandler5.5、设置 Channel 选项5.6、绑定端口启动服务 六、引导客户端…...
如何使用进行MQ中间件接口测试
进行MQ中间件接口测试时,需要按以下步骤进行: 1.配置测试环境 搭建MQ服务器环境,并确保连接配置正确,以及客户端SDK等相关依赖库和组件已安装并配置正确。 2.制定测试计划 测试人员需要根据具体业务场景和测试目的,制…...
Zebec生态进展迅速,频被BitFlow、Matryx DAO等蹭热度碰瓷
进入到 2023 年以来, Zebec 生态的整体发展突飞猛进,除了流支付协议 Zebec Protocol 不断通过收购来扩大自身流支付业务、与万事达等合作推出 Zebec Card 等在支付业务上,实现进展外,其社区驱动的Layer3 模块化链 Nautilus Chain …...
7种PCB走线方式
01电源布局布线相关 数字电路很多时候需要的电流是不连续的,所以对一些高速器件就会产生浪涌电流。 如果电源走线很长,则由于浪涌电流的存在进而会导致高频噪声,而此高频噪声会引入到其他信号中去。 而在高速电路中必然会存在寄生电感和寄…...
Rabbit SpringBoot高级用法
Rabbit高级用法 一、Rabbit Springboot集成1.1 引入依赖1.2 添加配置1.3 添加Config1.4 编写Consumer1.5 发送消息 二、Rabbit 高级用法2.1 消息发送前置处理器2.2 消息发送确认机制2.3 消息接收后处理器2.4 事务消息 一、Rabbit Springboot集成 1.1 引入依赖 <dependency…...
找不到vcruntime140.dll,无法继续执行代码?多种解决方法解析
找不到vcruntime140.dll,无法继续执行代码?当你在尝试运行某个程序时,突然弹出一条错误提示框,告诉你无法继续执行代码,因为找不到vcruntime140.dll。这个问题很常见,但是它可能会让你感到困惑和疑惑。这篇文章将详细介…...
自然语言处理实战项目8- BERT模型的搭建,训练BERT实现实体抽取识别的任务
大家好,我是微学AI,今天给大家介绍一下自然语言处理实战项目8- BERT模型的搭建,训练BERT实现实体抽取识别的任务。BERT模型是一种用于自然语言处理的深度学习模型,它可以通过训练来理解单词之间的上下文关系,从而为下游…...
pdf怎么合并在一起?软件操作更高效
PDF格式已经成为了许多文档和表格的首选格式。然而,当你需要合并多个PDF文件时,可能会遇到一些麻烦,在本篇文章中,我们将向您介绍一种简单易用的方法来合并PDF文件。 以下是可以用来合并PDF文件的软件: - PDF转换器&a…...
Junit常见用法
一.Junit的含义 Junit是一种Java编程语言的单元测试框架。它提供了一些用于编写和运行测试的注释和断言方法,并且可以方便地执行测试并生成测试报告。Junit是开源的,也是广泛使用的单元测试框架之一 二.Junit项目的创建 (1)先创…...
c++—内存管理、智能指针、内存池
1. 内存分析诊断工具:valgrind; 2. 内存管理的两种方式: ①用户管理:自己申请的,自己用,自己回收;效率高,但容易导致内存泄漏; ②系统管理:系统自动回收垃圾…...
JAVA使用HTTP代码示例
以下是使用Java发送HTTP请求的示例代码: java import java.io.BufferedReader; import java.io.InputStreamReader; import java.net.HttpURLConnection; import java.net.URL; public class HttpExample { public static void main(String[] args) { try { …...
【网络协议详解】——电子邮件系统协议(学习笔记)
目录 🕒 1. 电子邮件系统概述🕒 2. 简单邮件传送协议SMTP🕒 3. SMTP协议的命令和响应🕘 3.1 命令🕤 3.1.1 HELO🕤 3.1.2 MAIL FROM🕤 3.1.3 RCPT TO🕤 3.1.4 DATA🕤 3.1.…...
年度发布 | MeterSphere一站式开源持续测试平台发布v2.10 LTS版本
2023年5月25日,MeterSphere一站式开源持续测试平台正式发布v2.10 LTS版本。这是继2022年5月发布v1.20 LTS版本后,MeterSphere开源项目发布的第三个LTS(Long Term Support)版本。MeterSphere开源项目组将对MeterSphere v2.10 LTS版…...
从 OceanBase 迁移数据到 DolphinDB
OceanBase 是一款金融级分布式关系数据库,具有数据强一致、高可用、高性能、在线扩展、高度兼容 SQL标准和主流关系数据库、低成本等特点,但是其学习成本较高,且缺乏金融计算函数以及流式增量计算的功能。 DolphinDB 是一款国产的高性能分布…...
淘宝商品列表数据接口(支持价格、销量排序)
淘宝商品列表数据接口是淘宝提供的一种可以获取淘宝商品信息的接口。通过该接口,可以获取到具有一定规则的商品信息,例如按照价格排序、按照销量排序等。接口返回的数据格式为JSON格式,可以方便地处理数据。 我们可以通过调用淘宝提供的API&…...
Android 11 版本变更总览
Android 11 版本 Android 11 总览重大隐私权变更行为变更:所有应用行为变更:以 Android 11 为目标平台的应用功能和 API 概览Intent系统广播 intent(API 级别 30)通用应用 intent(API 级别 30) Android 11 …...
传染病学模型 | Matlab实现基于SIS传染病模型模拟城市内人口的互相感染及城市人口流动所造成的传染
文章目录 效果一览基本描述模型介绍程序设计参考资料效果一览 基本描述 传染病学模型 | Matlab实现基于SIS传染病模型模拟城市内人口的互相感染及城市人口流动所造成的传染 模型介绍 SIS模型是一种基本的传染病学模型,用于描述一个人群中某种传染病的传播情况。SIS模型假设每个…...
物联网技术如何改变我们的生活:一位资深物联网专家的见解
物联网(IoT)是指通过网络互联的物理设备、车辆、建筑物以及其他物品,这些物品都内置了传感器、执行器、软件和网络连接器,使它们能够收集和交换数据。物联网技术已经在各个领域产生了深远的影响,包括家庭、医疗、交通、…...
node.js+vue.js大学生在线选课系统的设计与实现93pul
本次设计任务是要设计一个选课系统的设计与实现,通过这个系统能够满足用户对选课信息的需求。系统的主要功能包括:个人中心、学生管理、教师管理、选课信息管理等功能。 管理员可以根据系统给定的账号进行登录,登录后可以进入选课系统的设计与…...
华为OD机试真题 Java 实现【寻找符合要求的最长子串】【2023Q1 200分】
一、题目描述 给定一个字符串 s ,找出这样一个子串: 该子串中的任意一个字符最多出现2次;该子串不包含指定某个字符;请你找出满足该条件的最长子串的长度。 二、输入描述 第一行为要求不包含的指定字符,为单个字符,取值范围[0-9a-zA-Z]。 第二行为字符串s,每个字符范…...
eNSP-Cloud(实现本地电脑与eNSP内设备之间通信)
说明: 想象一下,你正在用eNSP搭建一个虚拟的网络世界,里面有虚拟的路由器、交换机、电脑(PC)等等。这些设备都在你的电脑里面“运行”,它们之间可以互相通信,就像一个封闭的小王国。 但是&#…...
Android Wi-Fi 连接失败日志分析
1. Android wifi 关键日志总结 (1) Wi-Fi 断开 (CTRL-EVENT-DISCONNECTED reason3) 日志相关部分: 06-05 10:48:40.987 943 943 I wpa_supplicant: wlan0: CTRL-EVENT-DISCONNECTED bssid44:9b:c1:57:a8:90 reason3 locally_generated1解析: CTR…...
1688商品列表API与其他数据源的对接思路
将1688商品列表API与其他数据源对接时,需结合业务场景设计数据流转链路,重点关注数据格式兼容性、接口调用频率控制及数据一致性维护。以下是具体对接思路及关键技术点: 一、核心对接场景与目标 商品数据同步 场景:将1688商品信息…...
如何为服务器生成TLS证书
TLS(Transport Layer Security)证书是确保网络通信安全的重要手段,它通过加密技术保护传输的数据不被窃听和篡改。在服务器上配置TLS证书,可以使用户通过HTTPS协议安全地访问您的网站。本文将详细介绍如何在服务器上生成一个TLS证…...
现代密码学 | 椭圆曲线密码学—附py代码
Elliptic Curve Cryptography 椭圆曲线密码学(ECC)是一种基于有限域上椭圆曲线数学特性的公钥加密技术。其核心原理涉及椭圆曲线的代数性质、离散对数问题以及有限域上的运算。 椭圆曲线密码学是多种数字签名算法的基础,例如椭圆曲线数字签…...
Ascend NPU上适配Step-Audio模型
1 概述 1.1 简述 Step-Audio 是业界首个集语音理解与生成控制一体化的产品级开源实时语音对话系统,支持多语言对话(如 中文,英文,日语),语音情感(如 开心,悲伤)&#x…...
select、poll、epoll 与 Reactor 模式
在高并发网络编程领域,高效处理大量连接和 I/O 事件是系统性能的关键。select、poll、epoll 作为 I/O 多路复用技术的代表,以及基于它们实现的 Reactor 模式,为开发者提供了强大的工具。本文将深入探讨这些技术的底层原理、优缺点。 一、I…...
关键领域软件测试的突围之路:如何破解安全与效率的平衡难题
在数字化浪潮席卷全球的今天,软件系统已成为国家关键领域的核心战斗力。不同于普通商业软件,这些承载着国家安全使命的软件系统面临着前所未有的质量挑战——如何在确保绝对安全的前提下,实现高效测试与快速迭代?这一命题正考验着…...
PHP 8.5 即将发布:管道操作符、强力调试
前不久,PHP宣布了即将在 2025 年 11 月 20 日 正式发布的 PHP 8.5!作为 PHP 语言的又一次重要迭代,PHP 8.5 承诺带来一系列旨在提升代码可读性、健壮性以及开发者效率的改进。而更令人兴奋的是,借助强大的本地开发环境 ServBay&am…...
ubuntu22.04有线网络无法连接,图标也没了
今天突然无法有线网络无法连接任何设备,并且图标都没了 错误案例 往上一顿搜索,试了很多博客都不行,比如 Ubuntu22.04右上角网络图标消失 最后解决的办法 下载网卡驱动,重新安装 操作步骤 查看自己网卡的型号 lspci | gre…...
