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://www.mzph.cn/news/712963.shtml

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

相关文章

【LLM RAG】GritLM:统一嵌入和生成的大语言模型浅谈

前言 目前&#xff0c;所有基于文本的语言问题都可以归结为生成问题&#xff0c;并通过单一的LLM来处理。然而&#xff0c;使用嵌入的任务&#xff08;如聚类或检索&#xff09;在这种视角下往往被忽视了。文本嵌入在许多关键的实际应用中扮演着重要角色。如RAG&#xff0c;在…

AIGC下一步:如何用AI再度重构或优化媒体处理?

让媒资中“沉默的大多数”再次焕发光彩。 邹娟&#xff5c;演讲者 编者按 AIGC时代下&#xff0c;媒体内容生产领域随着AI的出现也涌现出更多的变化与挑战。面对AI的巨大冲击&#xff0c;如何优化或重构媒体内容生产技术架构&#xff1f;在多样的应用场景中媒体内容生产技术又…

JavaScript 基本数据类型的详解

JavaScript的基本数据类型 以下都是JS内置的几种类型 数据类型描述number数字&#xff0c;不区分整数和小数string字符串类型booleantrue 真, false 假undefined表示未定义的值null只有唯一的值 null&#xff0c;表示空值 number 数字类型 JavaScript 中不区分整数和浮点数&…

itertools, 一个超好用的Python库

前言 Python用来处理迭代器的工具你想到了啥&#xff1f;itertools 就是一个特别有用的库&#xff0c;它提供了一系列用于创建和操作迭代器的工具&#xff0c;以下是10个常用的操作&#xff0c;可用在实际工作中&#xff0c;熟练掌握这些操作&#xff0c;将极大提升你在 Pytho…

栈(顺序栈)实现Language C

###王道考研的学习领悟&#xff0c;个人喜好讲解清晰 何为栈&#xff1f; 定义:栈&#xff08;stack&#xff09;是只允许在一端进行插入或删除的线性表。 其重要术语&#xff1a;栈顶&#xff0c;栈底&#xff0c;空栈。 我们只需要把这个图看明白了&#xff0c;理解起来就…

学校机房Dev c++解决中文乱码问题

工具->编译选项->勾选 编译时加入以下命令 -fexec-charsetGBK -finput-charsetUTF-8 显示中文&#xff1a;工具->编辑器选项->去掉第一个的勾勾。

Github上最值得学习的10个Android开源项目,安卓面试题

1.Java语言进阶与Android相关技术核 Android应用是由Java语言进行开发的&#xff0c;SDK也是由Java语言编写&#xff0c;对于Android来说&#xff0c;只要SDK没有用Kotlin重写&#xff0c;那么Java语言是都需要学习的。而且Android APK的后台服务器程序大概率是Java语言构建&a…

【计算机网络】应用层自定义协议

自定义协议 一、为什么需要自定义协议&#xff1f;二、网络版计算器1. 基本要求2. 序列化和反序列化3. 代码实现&#xff08;1&#xff09;封装 socket&#xff08;2&#xff09;定制协议和序列化反序列化&#xff08;3&#xff09;客户端&#xff08;4&#xff09;计算器服务端…

Javaweb之SpringBootWeb案例之自动配置以及常见方案的详细解析

3.2 自动配置 我们讲解了SpringBoot当中起步依赖的原理&#xff0c;就是Maven的依赖传递。接下来我们解析下自动配置的原理&#xff0c;我们要分析自动配置的原理&#xff0c;首先要知道什么是自动配置。 3.2.1 概述 SpringBoot的自动配置就是当Spring容器启动后&#xff0c…

【论文笔记】An Effective Adversarial Attack on Person Re-Identification ...

原文标题&#xff08;文章标题处有字数限制&#xff09;&#xff1a; 《An Effective Adversarial Attack on Person Re-Identification in Video Surveillance via Dispersion Reduction》 Abstract 通过减少神经网络内部特征图的分散性攻击reid模型。 erbloo/Dispersion_r…

Vue3中组件通讯的方式

Vue3中组件通讯的方式 1 &#x1f916;GPT&#x1f916;: (答案有点问题混淆了vue2的内容) 父组件向子组件传递数据 props 子组件通过 props 属性从父组件接收数据。emit事件子组件通过emit 事件 子组件通过 emit事件子组件通过emit 发射事件向父组件发送消息。provide / in…

Chrome插件 | WEB 网页数据采集和爬虫程序

无边无形的互联网遍地是数据&#xff0c;品类丰富、格式繁多&#xff0c;包罗万象。数据采集&#xff0c;或说抓取&#xff0c;就是把分散各处的内容&#xff0c;通过各种方式汇聚一堂&#xff0c;是个有讲究要思考的体力活。君子爱数&#xff0c;取之有道&#xff0c;得注意遵…

mobile app 安全扫描工具MobSF了解下

可以干啥&#xff1a; static 静态分析 dynamic 动态分析 可以用来渗透了 如何docker安装 docker image 下载地址https://hub.docker.com/r/opensecurity/mobile-security-framework-mobsf/ setup 两行即可 1 docker pull opensecurity/mobile-security-framework-mobsf…

年轻人怎么搞钱?

年轻人想要搞钱&#xff0c;可以考虑以下几个方面&#xff1a; 1. 创业&#xff1a;年轻人可以通过自己的创意&#xff0c;找到一个市场的空缺&#xff0c;开创自己的业务。可以从比较小的项目开始&#xff0c;逐渐扩大范围&#xff0c;积累经验和财富。 2. 投资&#xff1a;…

Hadoop之HDFS——【模块二】数据管理

一、Namespace的概述 1.1.集群与命名空间的关系 类似于大集群与小集群之间的关系,彼此之间独立又相互依存。每个namespace彼此独立,Namespace工作时只负责维护本区域的数据,同时所有的namespace维护的文件都可以共用DataNode节点,为了区分数据属于哪些Namespace,DataNode…

强大而灵活的python装饰器

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

CrossOver 24下载-CrossOver 24 for Mac下载 v24.0.0中文永久版

CrossOver 24是一款可以让mac用户能够自由运行和游戏windows游戏软件的虚拟机类应用&#xff0c;虽然能够虚拟windows但是却并不是一款虚拟机&#xff0c;也不需要重启系统或者启动虚拟机&#xff0c;类似于一种能够让mac系统直接运行windows软件的插件。它以其出色的跨平台兼容…

NVMe开发——PCIe复位

简介 PCIe中有4种复位机制&#xff0c;早期的3种被称为传统复位(Conventional Reset)。传统复位中的前2种又称为基本复位(Fundamental Resets)&#xff0c;分别为冷复位(Cold Reset)&#xff0c;暖复位(Warm Reset)。第3种复位为热复位(Hot Reset)。第4种复位被称为功能级复位…

179基于matlab的2D-VMD处理图像

基于matlab的2D-VMD处理图像&#xff0c;将图片进行VMD分解&#xff0c;得到K个子模态图&#xff0c;将每个模态图进行重构&#xff0c;得到近似的原图。可以利用这点进行图像去噪。程序已调通&#xff0c;可直接运行。 179 2D-VMD 图像分解重构 图像处理 (xiaohongshu.com)

每日五道java面试题之spring篇(九)

目录&#xff1a; 第一题. 说一下Spring的事务传播行为第二题. 说一下 spring 的事务隔离&#xff1f;第三题. Spring AOP and AspectJ AOP 有什么区别&#xff1f;AOP 有哪些实现方式&#xff1f;第四题. JDK动态代理和CGLIB动态代理的区别第五题. 解释一下Spring AOP里面的几…