Spring Boot整合Kafka

文章目录

      • 1. 介绍
      • 2. Kafka基础
        • 2.1. 安装KafKa
        • kafka集群搭建_kafka交流群-CSDN博客
      • 3. Spring Boot整合Kafka
        • 3.1. 引入Kafka依赖
        • 3.2.编写配置文件
      • 4. 生产者(produced)
        • 4.1. 生产者基础案例(基础测试)
      • 5. 消费者
        • 5.1.消费者基本案例(基础测试)
      • 6.Kafka常用配置
        • kafka配置文件解释
          • producer.properties解释
          • consumer.properties解释
          • server.properties解释
      • 7.ACK
      • 8.查看指定分区的数据

1. 介绍

Kafka作为一款分布式流处理平台,具有高吞吐量、持久性、容错性等特点,适用于构建大规模的实时数据管道。

Spring Boot作为快速开发框架,提供了简化开发和部署的能力,使得与Kafka的整合变得更加容易。

通过将Spring Boot与Kafka进行整合,具有以下优势

  1. 异步消息处理:Kafka可以作为消息队列,实现异步消息的生产和消费,提高系统的吞吐量和响应速度。
  2. 解耦和扩展性:消息队列的引入可以解耦不同系统或模块之间的依赖关系,提高系统的灵活性和可维护性。
  3. 数据流处理:Kafka支持流处理,可以用于实时数据分析、日志收集、事件驱动等场景,为业务提供更多的数据洞察。
  4. 可靠性和容错性:Kafka具有高度可靠性和容错性,能够保证消息不丢失,并且支持分布式部署,保证系统的稳定性和可靠性。

Spring Boot与Kafka整合为开发者提供了一种强大的消息传递解决方案,能够满足现代分布式系统对于消息传递的需求,提高系统的性能、可维护性和可扩展性。

2. Kafka基础

2.1. 安装KafKa

可参考本篇博客

kafka集群搭建_kafka交流群-CSDN博客

Kafka的一些特点

  1. 发布订阅模型:
    • 生产者将消息发布到主题,消费者订阅这些主题以接收消息。
    • 每个主题可以有多个订阅者,消息会广播给所有订阅者。
  2. 消息日志:
    • Kafka将消息存储在持久化的日志中,每个消息都有一个唯一的偏移量。
    • 日志被分割成多个分区,每个分区中的消息有顺序的索引。
    • 分区允许Kafka在集群中并行处理和存储消息,提高了吞吐量和扩展性。
  3. 分布式架构:
    • Kafka是一个分布式系统,集群由多个Broker组成。
    • 每个分区有副本分布在不同的Broker上,确保消息的可靠性和容错性。
    • 分布式架构支持水平扩展,能够处理大规模的数据和高并发的请求。
  4. 高吞吐量:
    • Kafka被设计为高吞吐量的消息系统,能够处理每秒数百万条消息。
    • 高效的批量处理和零拷贝机制使得Kafka能够提供低延迟的消息传递服务。
  5. 持久性:
    • Kafka的消息是持久化存储的,可以通过配置持久化策略来保留消息的时间和大小。
    • 消息一旦被写入到Kafka中就不会丢失,即使消费者尚未处理。
  6. 水平扩展:
    • Kafka集群可以水平扩展,通过增加Broker和分区来提高系统的容量和吞吐量。
    • 新的Broker和分区可以动态地加入到集群中,而不会中断服务。
  7. 可靠性和容错性:
    • Kafka通过副本机制和ISR(In-Sync Replicas)机制实现高可靠性和容错性。
    • ISR机制确保了即使部分Broker失效,也能继续保持数据的一致性和可用性。
  8. 流处理:
    • Kafka Streams API提供了流处理的能力,允许开发者在Kafka中进行实时数据处理和分析。
    • 流处理功能使得Kafka能够更灵活地处理实时数据流和生成实时结果。

3. Spring Boot整合Kafka

3.1. 引入Kafka依赖

image-20240229213324522

<dependency><groupId>org.springframework.kafka</groupId><artifactId>spring-kafka</artifactId><version>2.9.13</version>
</dependency>gradle:
implementation 'org.springframework.kafka:spring-kafka:2.9.13'
3.2.编写配置文件
# 配置环境的 指定topic 如果有多个 可以使用 ,进行连接
dc:topics:info: ENTRY_USER_INFO# 指定 组idgroup-id: hrfan-consumer-group
spring:kafka:consumer:bootstrap-servers: 192.168.112.128:9092group-id: hrfan-consumer-groupauto-offset-reset: earliest# 错误处理key-deserializer: org.springframework.kafka.support.serializer.ErrorHandlingDeserializervalue-deserializer: org.springframework.kafka.support.serializer.ErrorHandlingDeserializerproperties:spring.json.trusted.packages: '*'# 序列化、反序列化一致spring.deserializer.key.delegate.class: org.apache.kafka.common.serialization.StringDeserializer# 注意 这里需要使用 org.apache.kafka.common.serialization.StringDeserializer# 不能使用 org.springframework.kafka.support.serializer.JsonSerializer 不然会报错 需要保持一致spring.deserializer.value.delegate.class: org.apache.kafka.common.serialization.StringDeserializerproducer:bootstrap-servers: 192.168.112.128:9092key-serializer: org.apache.kafka.common.serialization.StringSerializervalue-serializer: org.springframework.kafka.support.serializer.JsonSerializer

4. 生产者(produced)

4.1. 生产者基础案例(基础测试)
/*** 测试向Kafka发送消息** @author 13723* @version 1.0* 2024/3/1 10:35*/
@SpringBootTest
public class KafkaProducedTest {private static final Logger logger = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());@Value("${dc.topics.dutyform}")private String topics;/*** kafka模板 String消息*/@Resourceprivate KafkaTemplate<String, String> kafkaTemplate;/*** kafka模板 Message消息*/@Resourceprivate KafkaTemplate<String, Message<String>> kafkaTemplateMessage;@Test@DisplayName("测试向KfaKa发送消息")public void testSend() {// 发送普通消息kafkaTemplate.send(topics, "测试发送普通消息-无Key");// 发送Key-Value消息kafkaTemplate.send(topics, "hrfan-key-1", "测试发送key-Value消息");// 发送Partition(分区)-Offset(偏移量)消息// 在Apache Kafka中,消息被组织在称为"主题(Topics)"的逻辑类别中。// 每个主题可以被划分为一个或多个"分区(Partitions)"。分区是消息的物理存储单元,它们分布在不同的Kafka服务器上。// 每个分区中的消息都有一个唯一的编号,称为"偏移量(Offset)"。这个偏移量标识了消息在该分区中的位置。偏移量是一个递增的整数,新消息的偏移量比旧消息的偏移量大。kafkaTemplate.send(topics, 0, "hrfan-key-2", "测试发送Partition-Offset消息");// 可以理解为拼装JSON类型数据// 发送Message消息// 通过sendDefault()方法发送消息,消息将会被发送到默认的主题中。String event = "测试发送Message消息";Map<String, Object> map = new HashMap<>();map.put("token", UUID.randomUUID().toString());MessageHeaders headers = new MessageHeaders(map);Message<String> message = MessageBuilder.createMessage(event, headers);// 设置默认topickafkaTemplate.setDefaultTopic(topics);// 将消息发送到默认的topic// 注意此时修改 泛型为// @Resource// private KafkaTemplate<String,Message<String>> kafkaTemplateMessage;kafkaTemplateMessage.sendDefault("hrfan-key-3", message);logger.info("消息发送成功");}}

image-20240301133509648

image-20240301133913211

5. 消费者

5.1.消费者基本案例(基础测试)
/*** 模拟Kafka消费者* @author 13723* @version 1.0* 2024/2/29 17:01*/
@Component
public class KafkaCustomerDemo {private static final Logger logger = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());@KafkaListener(topics = "#{'${dc.topics.dutyform}'.split(',')}", groupId = "${dc.group-id}", autoStartup = "true")public void onMessageSync(ConsumerRecord<String, String> record,  @Headers Map<String,Object> headers) {logger.error("获取到的信息为:{},",record);}}

image-20240301133749367

6.Kafka常用配置

kafka配置文件解释
producer.properties解释
producer.properties:生产端的配置文件
#指定kafka节点列表,用于获取metadata,不必全部指定
#需要kafka的服务器地址,来获取每一个topic的分片数等元数据信息。
metadata.broker.list=kafka01:9092,kafka02:9092,kafka03:9092#生产者生产的消息被发送到哪个block,需要一个分组策略。
#指定分区处理类。默认kafka.producer.DefaultPartitioner,表通过key哈希到对应分区
#partitioner.class=kafka.producer.DefaultPartitioner#生产者生产的消息可以通过一定的压缩策略(或者说压缩算法)来压缩。消息被压缩后发送到broker集群,
#而broker集群是不会进行解压缩的,broker集群只会把消息发送到消费者集群,然后由消费者来解压缩。
#是否压缩,默认0表示不压缩,1表示用gzip压缩,2表示用snappy压缩。
#压缩后消息中会有头来指明消息压缩类型,故在消费者端消息解压是透明的无需指定。
#文本数据会以1比10或者更高的压缩比进行压缩。
compression.codec=none#指定序列化处理类,消息在网络上传输就需要序列化,它有String、数组等许多种实现。
serializer.class=kafka.serializer.DefaultEncoder#如果要压缩消息,这里指定哪些topic要压缩消息,默认empty,表示不压缩。
#如果上面启用了压缩,那么这里就需要设置
#compressed.topics= 
#这是消息的确认机制,默认值是0。在面试中常被问到。
#producer有个ack参数,有三个值,分别代表:
#(1)不在乎是否写入成功;
#(2)写入leader成功;
#(3)写入leader和所有副本都成功;
#要求非常可靠的话可以牺牲性能设置成最后一种。
#为了保证消息不丢失,至少要设置为1,也就
#是说至少保证leader将消息保存成功。
#设置发送数据是否需要服务端的反馈,有三个值0,1,-1,分别代表3种状态:
#0: producer不会等待broker发送ack。生产者只要把消息发送给broker之后,就认为发送成功了,这是第1种情况;
#1: 当leader接收到消息之后发送ack。生产者把消息发送到broker之后,并且消息被写入到本地文件,才认为发送成功,这是第二种情况;#-1: 当所有的follower都同步消息成功后发送ack。不仅是主的分区将消息保存成功了,
#而且其所有的分区的副本数也都同步好了,才会被认为发动成功,这是第3种情况。
request.required.acks=0#broker必须在该时间范围之内给出反馈,否则失败。
#在向producer发送ack之前,broker允许等待的最大时间 ,如果超时,
#broker将会向producer发送一个error ACK.意味着上一次消息因为某种原因
#未能成功(比如follower未能同步成功)
request.timeout.ms=10000#生产者将消息发送到broker,有两种方式,一种是同步,表示生产者发送一条,broker就接收一条;
#还有一种是异步,表示生产者积累到一批的消息,装到一个池子里面缓存起来,再发送给broker,
#这个池子不会无限缓存消息,在下面,它分别有一个时间限制(时间阈值)和一个数量限制(数量阈值)的参数供我们来设置。
#一般我们会选择异步。
#同步还是异步发送消息,默认“sync”表同步,"async"表异步。异步可以提高发送吞吐量,
#也意味着消息将会在本地buffer中,并适时批量发送,但是也可能导致丢失未发送过去的消息
producer.type=sync#在async模式下,当message被缓存的时间超过此值后,将会批量发送给broker,
#默认为5000ms
#此值和batch.num.messages协同工作.
queue.buffering.max.ms = 5000#异步情况下,缓存中允许存放消息数量的大小。
#在async模式下,producer端允许buffer的最大消息量
#无论如何,producer都无法尽快的将消息发送给broker,从而导致消息在producer端大量沉积
#此时,如果消息的条数达到阀值,将会导致producer端阻塞或者消息被抛弃,默认为10000条消息。
queue.buffering.max.messages=20000#如果是异步,指定每次批量发送数据量,默认为200
batch.num.messages=500#在生产端的缓冲池中,消息发送出去之后,在没有收到确认之前,该缓冲池中的消息是不能被删除的,
#但是生产者一直在生产消息,这个时候缓冲池可能会被撑爆,所以这就需要有一个处理的策略。
#有两种处理方式,一种是让生产者先别生产那么快,阻塞一下,等会再生产;另一种是将缓冲池中的消息清空。
#当消息在producer端沉积的条数达到"queue.buffering.max.meesages"后阻塞一定时间后,
#队列仍然没有enqueue(producer仍然没有发送出任何消息)
#此时producer可以继续阻塞或者将消息抛弃,此timeout值用于控制"阻塞"的时间
#-1: 不限制阻塞超时时间,让produce一直阻塞,这个时候消息就不会被抛弃
#0: 立即清空队列,消息被抛弃
queue.enqueue.timeout.ms=-1#当producer接收到error ACK,或者没有接收到ACK时,允许消息重发的次数
#因为broker并没有完整的机制来避免消息重复,所以当网络异常时(比如ACK丢失)
#有可能导致broker接收到重复的消息,默认值为3.
message.send.max.retries=3#producer刷新topic metada的时间间隔,producer需要知道partition leader
#的位置,以及当前topic的情况
#因此producer需要一个机制来获取最新的metadata,当producer遇到特定错误时,
#将会立即刷新
#(比如topic失效,partition丢失,leader失效等),此外也可以通过此参数来配置
#额外的刷新机制,默认值600000
topic.metadata.refresh.interval.ms=60000
consumer.properties解释
#消费者集群通过连接Zookeeper来找到broker。
#zookeeper连接服务器地址
zookeeper.connect=zk01:2181,zk02:2181,zk03:2181#zookeeper的session过期时间,默认5000ms,用于检测消费者是否挂掉
zookeeper.session.timeout.ms=5000#当消费者挂掉,其他消费者要等该指定时间才能检查到并且触发重新负载均衡
zookeeper.connection.timeout.ms=10000#这是一个时间阈值。
#指定多久消费者更新offset到zookeeper中。
#注意offset更新时基于time而不是每次获得的消息。
#一旦在更新zookeeper发生异常并重启,将可能拿到已拿到过的消息
zookeeper.sync.time.ms=2000#指定消费
group.id=xxxxx#这是一个数量阈值,经测试是500条。
#当consumer消费一定量的消息之后,将会自动向zookeeper提交offset信息#注意offset信息并不是每消费一次消息就向zk提交
#一次,而是现在本地保存(内存),并定期提交,默认为true
auto.commit.enable=true# 自动更新时间。默认60 * 1000
auto.commit.interval.ms=1000# 当前consumer的标识,可以设定,也可以有系统生成,
#主要用来跟踪消息消费情况,便于观察
conusmer.id=xxx# 消费者客户端编号,用于区分不同客户端,默认客户端程序自动产生
client.id=xxxx# 最大取多少块缓存到消费者(默认10)
queued.max.message.chunks=50# 当有新的consumer加入到group时,将会reblance,此后将会
#有partitions的消费端迁移到新  的consumer上,如果一个
#consumer获得了某个partition的消费权限,那么它将会向zk
#注册 "Partition Owner registry"节点信息,但是有可能
#此时旧的consumer尚没有释放此节点, 此值用于控制,
#注册节点的重试次数.
rebalance.max.retries=5#每拉取一批消息的最大字节数
#获取消息的最大尺寸,broker不会像consumer输出大于
#此值的消息chunk 每次feth将得到多条消息,此值为总大小,
#提升此值,将会消耗更多的consumer端内存
fetch.min.bytes=6553600#当消息的尺寸不足时,server阻塞的时间,如果超时,
#消息将立即发送给consumer
#数据一批一批到达,如果每一批是10条消息,如果某一批还
#不到10条,但是超时了,也会立即发送给consumer。
fetch.wait.max.ms=5000
socket.receive.buffer.bytes=655360# 如果zookeeper没有offset值或offset值超出范围。
#那么就给个初始的offset。有smallest、largest、
#anything可选,分别表示给当前最小的offset、
#当前最大的offset、抛异常。默认largest
auto.offset.reset=smallest# 指定序列化处理类
derializer.class=kafka.serializer.DefaultDecoder
server.properties解释
server.properties:服务端的配置文件
#broker的全局唯一编号,不能重复
broker.id=0#用来监听链接的端口,producer或consumer将在此端口建立连接
port=9092#处理网络请求的线程数量,也就是接收消息的线程数。
#接收线程会将接收到的消息放到内存中,然后再从内存中写入磁盘。
num.network.threads=3#消息从内存中写入磁盘是时候使用的线程数量。
#用来处理磁盘IO的线程数量
num.io.threads=8#发送套接字的缓冲区大小
socket.send.buffer.bytes=102400#接受套接字的缓冲区大小
socket.receive.buffer.bytes=102400#请求套接字的缓冲区大小
socket.request.max.bytes=104857600#kafka运行日志存放的路径
log.dirs=/export/servers/logs/kafka#topic在当前broker上的分片个数
num.partitions=2#我们知道segment文件默认会被保留7天的时间,超时的话就
#会被清理,那么清理这件事情就需要有一些线程来做。这里就是
#用来设置恢复和清理data下数据的线程数量
num.recovery.threads.per.data.dir=1#segment文件保留的最长时间,默认保留7天(168小时),
#超时将被删除,也就是说7天之前的数据将被清理掉。
log.retention.hours=168#滚动生成新的segment文件的最大时间
log.roll.hours=168#日志文件中每个segment的大小,默认为1G
log.segment.bytes=1073741824#上面的参数设置了每一个segment文件的大小是1G,那么
#就需要有一个东西去定期检查segment文件有没有达到1G,
#多长时间去检查一次,就需要设置一个周期性检查文件大小
#的时间(单位是毫秒)。
log.retention.check.interval.ms=300000#日志清理是否打开
log.cleaner.enable=true#broker需要使用zookeeper保存meta数据
zookeeper.connect=zk01:2181,zk02:2181,zk03:2181#zookeeper链接超时时间
zookeeper.connection.timeout.ms=6000#上面我们说过接收线程会将接收到的消息放到内存中,然后再从内存
#写到磁盘上,那么什么时候将消息从内存中写入磁盘,就有一个
#时间限制(时间阈值)和一个数量限制(数量阈值),这里设置的是
#数量阈值,下一个参数设置的则是时间阈值。
#partion buffer中,消息的条数达到阈值,将触发flush到磁盘。
log.flush.interval.messages=10000#消息buffer的时间,达到阈值,将触发将消息从内存flush到磁盘,
#单位是毫秒。
log.flush.interval.ms=3000#删除topic需要server.properties中设置delete.topic.enable=true否则只是标记删除
delete.topic.enable=true#此处的host.name为本机IP(重要),如果不改,则客户端会抛出:
#Producer connection to localhost:9092 unsuccessful 错误!
host.name=kafka01advertised.host.name=192.168.239.128

7.ACK

什么是ACK?

​ 在Apache Kafka中,“Ack” 是 “Acknowledgement” 的缩写,用于表示生产者(producer)发送消息给 Kafka 服务器后,服务器返回的确认信息。

Kafka提供了三种ACK级别

  • acks=0:生产者发送消息后,不等待任何确认,直接发送下一条消息。
  • acks=1:生产者发送消息后,等待leader节点成功写入消息后返回确认,然后发送下一条消息。
  • acks=all:生产者发送消息后,等待所有的follower节点和leader节点都成功写入消息后返回确认,然后发送下一条消息。

acks=all 是最安全的设置,但是也会导致最慢的性能,因为要等待多个副本的确认。

image-20240301183001141

  • 生产者(produced)发送消息到 leaderleader收到消息会发送ACK
    • leader负责处理读写操作
      • 如果leader出现故障,会从follwer中重新选取leader
    • follower负责副本数据之间的同步
      • follower可以理解为自动备份,会不断从对应分区拉取leader的数据,对数据进行存储
  • leaderfollower 之间同步数据也会发送ACK

在Spring-Kafka中,提供了集中AckMode模式

org.springframework.kafka.listener.ContainerProperties.AckMode
public static enum AckMode {RECORD,BATCH,TIME,COUNT,COUNT_TIME,MANUAL,MANUAL_IMMEDIATE;private AckMode() {}
}
  1. RECORD:每处理一条消息后立即发送确认。这意味着每处理一条消息,消费者都会向 Kafka 代理发送一个确认消息。
  2. BATCH:批量确认模式。消费者将处理一批消息后才发送一次确认。这种模式可以减少确认消息的数量,提高性能。
  3. TIME:定时确认模式。消费者将在一定时间间隔内处理的所有消息后发送一次确认。这可以控制确认消息的发送频率。
  4. COUNT:计数确认模式。消费者将处理一定数量的消息后发送一次确认。这种模式也有助于控制确认消息的发送频率。
  5. COUNT_TIME:结合了计数和定时的确认模式。消费者将在达到一定数量的消息或一定时间间隔内发送一次确认,以提高灵活性和性能。
  6. MANUAL:手动确认模式。消费者需要在处理消息后显式地调用确认操作,以告知 Kafka 代理消息已被处理。
  7. MANUAL_IMMEDIATE:立即手动确认模式。与上述手动确认模式类似,但在调用确认操作后立即发送确认,而不是等待一定的时间或数量。

7.1手动提交ACK

Kafka中ACK默认是自动提交的,在开发中,有时候我们需要进行手动提交ACK,那么在配置中我们可以做如下修改

  • 禁止自动提交enable-auto-commit=false
  • 设置ack-modemanual_immediat(立即手动确认模式)
	@KafkaListener(topics = "#{'${dc.topics.user}'.split(',')}", groupId = "${dc.group-id}", autoStartup = "true")public void onMessageSync(ConsumerRecord<String, String> record,  @Headers Map<String,Object> headers,Acknowledgment ack) {logger.error("获取到的信息为:{},",record);//手动提交offset// ack.acknowledge();}

image-20240301201320109

image-20240301201438112

image-20240301201524566

8.查看指定分区的数据

有时候需要在服务器上查询一些分区的数据,可以使用 kafka提供的工具 kafka-console-consumer

kafka-console-consumer --bootstrap-server 192.168.112.129:9092 --topic ENTRY_LIST_SEND_INFO --from-beginning

image-20240301171337018

image-20240301171647186

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

如若内容造成侵权/违法违规/事实不符,请联系瞎胡闹网进行投诉反馈,一经查实,立即删除!

相关文章

python 公共函数及操作符使用示例合集

python公共操作符以及方法是什么 在Python中&#xff0c;公共操作通常指的是那些可以对不同数据类型&#xff08;如数字、字符串、列表、元组、字典等&#xff09;进行操作的通用函数或方法。这些操作符或函数通常是内置的&#xff0c;并且可以在Python的官方文档中找到。 主要…

数字电路 第五章—第四节(顺序脉冲发生器)

一、计数型顺序脉冲发生器 1、电路组成 计数型顺序脉冲发生器一般都是按自然态序计数的二进制计数器和译码器组成。 2、输出4个脉冲的顺序脉冲发生器 &#xff08;1&#xff09;逻辑电路图&#xff08;采用JK触发器&#xff09;&#xff1a; &#xff08;2&#xff09;时序图…

二叉搜索树的范围和(Lc938)——DFS

给定二叉搜索树的根结点 root&#xff0c;返回值位于范围 [low, high] 之间的所有结点的值的和。 示例 1&#xff1a; 输入&#xff1a;root [10,5,15,3,7,null,18], low 7, high 15 输出&#xff1a;32示例 2&#xff1a; 输入&#xff1a;root [10,5,15,3,7,13,18,1,nul…

家居清洁必备:2024如何挑选高效家用洗地机的实用指南

对于养宠物的家庭来说&#xff0c;宠物的毛发无处不在&#xff0c;尤其在换毛季节&#xff0c;清理工作更加繁琐。此时&#xff0c;洗地机的出现为解决这些问题提供了便利。洗地机可以同时扫地和拖地&#xff0c;实现高效清洁&#xff0c;减轻了清洁负担。而且&#xff0c;洗地…

【爬虫逆向实战 逆向滑块 Python+Node】今天逆向的网站有点嘿嘿,还是仅供学习,别瞎搞

逆向日期&#xff1a;2024.03.01 使用工具&#xff1a;Node.js、Python 加密方法&#xff1a;AES标准算法 文章全程已做去敏处理&#xff01;&#xff01;&#xff01; 【需要做的可联系我】 AES解密处理&#xff08;直接解密即可&#xff09;&#xff08;crypto-js.js 标准算…

windows系统安装《植物大战僵尸2009原版》教程

本文演示如何在windows免费安装 植物大战僵尸2009原版。 首先到 点此下载安装包 此页面最末端下载百度网盘分享的安装包。 下载完成后安装如下步骤进行安装&#xff1a; 安装完成即可开心的玩耍啦&#xff01; 我自己的安装过程录屏在这里 https://www.bilibili.com/vid…

新 Logo 正式发布,Tubi 品牌全面升级!

作为新一代观众的首选流媒体平台&#xff0c;Tubi 持续扩大自身影响力&#xff0c;并于近日推出了富有活力的新品牌形象。 根据 Nielsen 的 The Gauge 报告&#xff0c;Tubi 在 2024 年 1 月的电视总观看份额提升至 1.5%&#xff0c;在年轻人和多元化观众群体中的吸引力持续上升…

MYSQL--JDBC优化

一.JDBC优化: 优化前提: 有时候我们并不清楚某些表当中一共有多少列,以及这些列的数据类型,这个时候我们就需要提前通过一些方法提前了解到这些数据,从而更好的进行输出 具体语句: package cn.jdbc;import java.sql.*;public class JDBCDEmo1 {public static void main(String…

11.盛最多水的容器

题目&#xff1a;给定一个长度为 n 的整数数组 height 。有 n 条垂线&#xff0c;第 i 条线的两个端点是 (i, 0) 和 (i, height[i]) 。 找出其中的两条线&#xff0c;使得它们与 x 轴共同构成的容器可以容纳最多的水。 返回容器可以储存的最大水量。 解题思路&#xff1a;可以…

2023 re:Invent AI 生成产品体验,从 Bedrock 到 Amazon Q

引 如果你也有如下问题&#xff0c;那么接下来的文字会一一为你解答 一套数据集&#xff0c;如何微调不同类型的开源大模型&#xff1f;—— Bedrock 如何只有产品说明书&#xff0c;如何构建一个智能问答机器人&#xff1f;—— Q 哪里还有免费的 GPU 算力——在线 Jupyter…

JQMobile Loader Widget 遮罩层改造

最近在用jqmobile 做一个混合APP项目时候用到 jqmobile1.4.3提供的Loader Widget控件,但是这个控件本身是一个loading弹出层,这个弹出层弹出之后,用户还是可以去点击按钮,重复发送请求,为了防止重复提交,我想了两种办法, 1,在loading弹出层弹出之后,让按钮不可用.但是form表单…

DC28V270V转AC36V115V航空逆变器

在当今的航空航天电源行业中&#xff0c;DC28V270V转AC36V115V航空逆变器发挥着至关重要的作用。作为一种关键的逆变器电源设备&#xff0c;DC28V270V转AC36V115V航空逆变器不仅在航空领域有着广泛的应用&#xff0c;还在许多其他领域发挥着重要作用。 一、DC28V270V转AC36V11…

源码的角度分析Vue2数据双向绑定原理

什么是双向绑定 我们先从单向绑定切入&#xff0c;其实单向绑定非常简单&#xff0c;就是把Model绑定到View&#xff0c;当我们用JavaScript代码更新Model时&#xff0c;View就会自动更新。那么双向绑定就可以从此联想到&#xff0c;即在单向绑定的基础上&#xff0c;用户更新…

GoFrame:如何简单地搭建一个简单地微服务

一切资料来源于GoFrame官网, 感兴趣的, 可以直接去官网查阅相关资料。 首先下载框架工具, 下载地址:https://github.com/gogf/gf/releases 然后进入你想要放置的项目文件夹, 执行命令行 gf init {project_name} #project_name为你的项目名 执行完后项目结构如图所示 然…

Java ElasticSearch-Linux面试题

Java ElasticSearch-Linux面试题 前言1、守护线程的作用&#xff1f;2、链路追踪Skywalking用过吗&#xff1f;3、你对G1收集器了解吗&#xff1f;4、你们项目用的什么垃圾收集器&#xff1f;5、内存溢出和内存泄露的区别&#xff1f;6、什么是Spring Cloud Bus&#xff1f;7、…

Java构造方法总结(很清晰)

构造方法扫盲&#xff1a;构造方法就是为了创建对象的 解释&#xff1a;真正创建对象的是 new 这个关键字&#xff0c;Java 虚拟机在创建对象时是有很多步骤的&#xff0c;构造方法只是其中的一步&#xff0c;它的作用是进行成员变量初始化。

AI大预言模型——ChatGPT在地学、GIS、气象、农业、生态、环境等应用

原文链接&#xff1a;AI大预言模型——ChatGPT在地学、GIS、气象、农业、生态、环境等应用 一开启大模型 1 开启大模型 1)大模型的发展历程与最新功能 2)大模型的强大功能与应用场景 3)国内外经典大模型&#xff08;ChatGPT、LLaMA、Gemini、DALLE、Midjourney、Stable Di…

强大而灵活的python装饰器

装饰器&#xff08;Decorators&#xff09; 一、概述 在Python中&#xff0c;装饰器是一种特殊类型的函数&#xff0c;它允许我们修改或增强其他函数的功能&#xff0c;而无需修改其源代码。装饰器在函数定义之后立即调用&#xff0c;并以函数对象作为参数。装饰器返回一个新…

微信小程序云开发教程——墨刀原型工具入门(安装以及基础使用教程)

引言 作为一个小白&#xff0c;小北要怎么在短时间内快速学会微信小程序原型设计&#xff1f; “时间紧&#xff0c;任务重”&#xff0c;这意味着学习时必须把握微信小程序原型设计中的重点、难点&#xff0c;而非面面俱到。 要在短时间内理解、掌握一个工具的使用&#xf…

储能:储能大会“共建储能生态链,共创储能新发展”

数字储能网讯&#xff1a;由中国化学与物理电源行业协会主办&#xff0c;中国化学与物理电源行业协会储能应用分会和中国储能网联合承办的第十四届中国国际储能大会暨展览会将于2024年3月10-12日在杭州国际博览中心召开&#xff0c;大会主题为“共建储能生态链&#xff0c;共创…