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

【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中间件接口测试时&#xff0c;需要按以下步骤进行&#xff1a; 1.配置测试环境 搭建MQ服务器环境&#xff0c;并确保连接配置正确&#xff0c;以及客户端SDK等相关依赖库和组件已安装并配置正确。 2.制定测试计划 测试人员需要根据具体业务场景和测试目的&#xff0c;制…...

Zebec生态进展迅速,频被BitFlow、Matryx DAO等蹭热度碰瓷

进入到 2023 年以来&#xff0c; Zebec 生态的整体发展突飞猛进&#xff0c;除了流支付协议 Zebec Protocol 不断通过收购来扩大自身流支付业务、与万事达等合作推出 Zebec Card 等在支付业务上&#xff0c;实现进展外&#xff0c;其社区驱动的Layer3 模块化链 Nautilus Chain …...

7种PCB走线方式

01电源布局布线相关 数字电路很多时候需要的电流是不连续的&#xff0c;所以对一些高速器件就会产生浪涌电流。 如果电源走线很长&#xff0c;则由于浪涌电流的存在进而会导致高频噪声&#xff0c;而此高频噪声会引入到其他信号中去。 而在高速电路中必然会存在寄生电感和寄…...

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,无法继续执行代码&#xff1f;当你在尝试运行某个程序时&#xff0c;突然弹出一条错误提示框&#xff0c;告诉你无法继续执行代码&#xff0c;因为找不到vcruntime140.dll。这个问题很常见&#xff0c;但是它可能会让你感到困惑和疑惑。这篇文章将详细介…...

自然语言处理实战项目8- BERT模型的搭建,训练BERT实现实体抽取识别的任务

大家好&#xff0c;我是微学AI&#xff0c;今天给大家介绍一下自然语言处理实战项目8- BERT模型的搭建&#xff0c;训练BERT实现实体抽取识别的任务。BERT模型是一种用于自然语言处理的深度学习模型&#xff0c;它可以通过训练来理解单词之间的上下文关系&#xff0c;从而为下游…...

pdf怎么合并在一起?软件操作更高效

PDF格式已经成为了许多文档和表格的首选格式。然而&#xff0c;当你需要合并多个PDF文件时&#xff0c;可能会遇到一些麻烦&#xff0c;在本篇文章中&#xff0c;我们将向您介绍一种简单易用的方法来合并PDF文件。 以下是可以用来合并PDF文件的软件&#xff1a; - PDF转换器&a…...

Junit常见用法

一.Junit的含义 Junit是一种Java编程语言的单元测试框架。它提供了一些用于编写和运行测试的注释和断言方法&#xff0c;并且可以方便地执行测试并生成测试报告。Junit是开源的&#xff0c;也是广泛使用的单元测试框架之一 二.Junit项目的创建 &#xff08;1&#xff09;先创…...

c++—内存管理、智能指针、内存池

1. 内存分析诊断工具&#xff1a;valgrind&#xff1b; 2. 内存管理的两种方式&#xff1a; ①用户管理&#xff1a;自己申请的&#xff0c;自己用&#xff0c;自己回收&#xff1b;效率高&#xff0c;但容易导致内存泄漏&#xff1b; ②系统管理&#xff1a;系统自动回收垃圾…...

JAVA使用HTTP代码示例

以下是使用Java发送HTTP请求的示例代码&#xff1a; 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 { …...

【网络协议详解】——电子邮件系统协议(学习笔记)

目录 &#x1f552; 1. 电子邮件系统概述&#x1f552; 2. 简单邮件传送协议SMTP&#x1f552; 3. SMTP协议的命令和响应&#x1f558; 3.1 命令&#x1f564; 3.1.1 HELO&#x1f564; 3.1.2 MAIL FROM&#x1f564; 3.1.3 RCPT TO&#x1f564; 3.1.4 DATA&#x1f564; 3.1.…...

年度发布 | MeterSphere一站式开源持续测试平台发布v2.10 LTS版本

2023年5月25日&#xff0c;MeterSphere一站式开源持续测试平台正式发布v2.10 LTS版本。这是继2022年5月发布v1.20 LTS版本后&#xff0c;MeterSphere开源项目发布的第三个LTS&#xff08;Long Term Support&#xff09;版本。MeterSphere开源项目组将对MeterSphere v2.10 LTS版…...

从 OceanBase 迁移数据到 DolphinDB

OceanBase 是一款金融级分布式关系数据库&#xff0c;具有数据强一致、高可用、高性能、在线扩展、高度兼容 SQL标准和主流关系数据库、低成本等特点&#xff0c;但是其学习成本较高&#xff0c;且缺乏金融计算函数以及流式增量计算的功能。 DolphinDB 是一款国产的高性能分布…...

淘宝商品列表数据接口(支持价格、销量排序)

淘宝商品列表数据接口是淘宝提供的一种可以获取淘宝商品信息的接口。通过该接口&#xff0c;可以获取到具有一定规则的商品信息&#xff0c;例如按照价格排序、按照销量排序等。接口返回的数据格式为JSON格式&#xff0c;可以方便地处理数据。 我们可以通过调用淘宝提供的API&…...

Android 11 版本变更总览

Android 11 版本 Android 11 总览重大隐私权变更行为变更&#xff1a;所有应用行为变更&#xff1a;以 Android 11 为目标平台的应用功能和 API 概览Intent系统广播 intent&#xff08;API 级别 30&#xff09;通用应用 intent&#xff08;API 级别 30&#xff09; Android 11 …...

传染病学模型 | Matlab实现基于SIS传染病模型模拟城市内人口的互相感染及城市人口流动所造成的传染

文章目录 效果一览基本描述模型介绍程序设计参考资料效果一览 基本描述 传染病学模型 | Matlab实现基于SIS传染病模型模拟城市内人口的互相感染及城市人口流动所造成的传染 模型介绍 SIS模型是一种基本的传染病学模型,用于描述一个人群中某种传染病的传播情况。SIS模型假设每个…...

物联网技术如何改变我们的生活:一位资深物联网专家的见解

物联网&#xff08;IoT&#xff09;是指通过网络互联的物理设备、车辆、建筑物以及其他物品&#xff0c;这些物品都内置了传感器、执行器、软件和网络连接器&#xff0c;使它们能够收集和交换数据。物联网技术已经在各个领域产生了深远的影响&#xff0c;包括家庭、医疗、交通、…...

node.js+vue.js大学生在线选课系统的设计与实现93pul

本次设计任务是要设计一个选课系统的设计与实现&#xff0c;通过这个系统能够满足用户对选课信息的需求。系统的主要功能包括&#xff1a;个人中心、学生管理、教师管理、选课信息管理等功能。 管理员可以根据系统给定的账号进行登录&#xff0c;登录后可以进入选课系统的设计与…...

华为OD机试真题 Java 实现【寻找符合要求的最长子串】【2023Q1 200分】

一、题目描述 给定一个字符串 s ,找出这样一个子串: 该子串中的任意一个字符最多出现2次;该子串不包含指定某个字符;请你找出满足该条件的最长子串的长度。 二、输入描述 第一行为要求不包含的指定字符,为单个字符,取值范围[0-9a-zA-Z]。 第二行为字符串s,每个字符范…...

【JavaEE】-- HTTP

1. HTTP是什么&#xff1f; HTTP&#xff08;全称为"超文本传输协议"&#xff09;是一种应用非常广泛的应用层协议&#xff0c;HTTP是基于TCP协议的一种应用层协议。 应用层协议&#xff1a;是计算机网络协议栈中最高层的协议&#xff0c;它定义了运行在不同主机上…...

React Native 开发环境搭建(全平台详解)

React Native 开发环境搭建&#xff08;全平台详解&#xff09; 在开始使用 React Native 开发移动应用之前&#xff0c;正确设置开发环境是至关重要的一步。本文将为你提供一份全面的指南&#xff0c;涵盖 macOS 和 Windows 平台的配置步骤&#xff0c;如何在 Android 和 iOS…...

智能分布式爬虫的数据处理流水线优化:基于深度强化学习的数据质量控制

在数字化浪潮席卷全球的今天&#xff0c;数据已成为企业和研究机构的核心资产。智能分布式爬虫作为高效的数据采集工具&#xff0c;在大规模数据获取中发挥着关键作用。然而&#xff0c;传统的数据处理流水线在面对复杂多变的网络环境和海量异构数据时&#xff0c;常出现数据质…...

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…...

C++使用 new 来创建动态数组

问题&#xff1a; 不能使用变量定义数组大小 原因&#xff1a; 这是因为数组在内存中是连续存储的&#xff0c;编译器需要在编译阶段就确定数组的大小&#xff0c;以便正确地分配内存空间。如果允许使用变量来定义数组的大小&#xff0c;那么编译器就无法在编译时确定数组的大…...

智能AI电话机器人系统的识别能力现状与发展水平

一、引言 随着人工智能技术的飞速发展&#xff0c;AI电话机器人系统已经从简单的自动应答工具演变为具备复杂交互能力的智能助手。这类系统结合了语音识别、自然语言处理、情感计算和机器学习等多项前沿技术&#xff0c;在客户服务、营销推广、信息查询等领域发挥着越来越重要…...

C#中的CLR属性、依赖属性与附加属性

CLR属性的主要特征 封装性&#xff1a; 隐藏字段的实现细节 提供对字段的受控访问 访问控制&#xff1a; 可单独设置get/set访问器的可见性 可创建只读或只写属性 计算属性&#xff1a; 可以在getter中执行计算逻辑 不需要直接对应一个字段 验证逻辑&#xff1a; 可以…...

虚拟电厂发展三大趋势:市场化、技术主导、车网互联

市场化&#xff1a;从政策驱动到多元盈利 政策全面赋能 2025年4月&#xff0c;国家发改委、能源局发布《关于加快推进虚拟电厂发展的指导意见》&#xff0c;首次明确虚拟电厂为“独立市场主体”&#xff0c;提出硬性目标&#xff1a;2027年全国调节能力≥2000万千瓦&#xff0…...

掌握 HTTP 请求:理解 cURL GET 语法

cURL 是一个强大的命令行工具&#xff0c;用于发送 HTTP 请求和与 Web 服务器交互。在 Web 开发和测试中&#xff0c;cURL 经常用于发送 GET 请求来获取服务器资源。本文将详细介绍 cURL GET 请求的语法和使用方法。 一、cURL 基本概念 cURL 是 "Client URL" 的缩写…...

系统掌握PyTorch:图解张量、Autograd、DataLoader、nn.Module与实战模型

本文较长&#xff0c;建议点赞收藏&#xff0c;以免遗失。更多AI大模型应用开发学习视频及资料&#xff0c;尽在聚客AI学院。 本文通过代码驱动的方式&#xff0c;系统讲解PyTorch核心概念和实战技巧&#xff0c;涵盖张量操作、自动微分、数据加载、模型构建和训练全流程&#…...