Spring-Kafka 发送消息的两种写法

文章目录

  • 前言
  • 写法一:发送的消息对象是字符串
    • 1 创建项目
    • 2 项目结构
    • 3 application.yml 配置文件
    • 4 生产者 KafkaProducerComponent
    • 5 消费者 KafkaConsumerComponent
    • 6 控制器(GET请求发送消息)
    • 7 启动类
    • 8 测试效果
  • 写法二:发送复杂消息对象
    • 1 创建项目
    • 2 项目结构
    • 3 application.yml 配置文件
    • 4 信任的包中定义的实体类
      • 4.1 kafka 消息接口规则定义
      • 4.2 测试实体定义
    • 5 生产者 KafkaObjectSerializerProducerComponent
    • 6 消费者 KafkaObjectSerializerConsumerComponent
    • 7 控制器(GET请求发送消息)
    • 8 启动类
    • 9 测试效果
  • 附录
    • 1 减少日志输出
    • 2 手动提交偏移量

前言

本文主要是使用 Java 语言中 spring-kafka 依赖 对 Kafka 进行使用。

使用以下依赖对 Kafka 进行操作:

<!-- https://mvnrepository.com/artifact/org.springframework.kafka/spring-kafka -->
<dependency>
    <groupId>org.springframework.kafka</groupId>
    <artifactId>spring-kafka</artifactId>
    <version>2.8.11</version>
</dependency>

需要更改版本的话,可以前往:Maven 仓库

创建项目,先创建一个简单的 Maven 项目,删除无用的包、类之后,使用其作为一个父级项目。
以下内容如果在项目启动时报这个错:

org.yaml.snakeyaml.error.YAMLException: java.nio.charset.MalformedInputException: Input length = 1

把注释删除就可以了。

写法一:发送的消息对象是字符串

1 创建项目

随后创建SpringBoot模块。选择 Kafka 组件

在这里插入图片描述

随后调整该项目的POM依赖为:

<dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.kafka</groupId>
            <artifactId>spring-kafka</artifactId>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.8.1</version>
                <configuration>
                    <source>11</source>
                    <target>11</target>
                    <encoding>UTF-8</encoding>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

注意这一步同时需要将Java版本、Maven版本都调整好。我这里目前使用的是Java11。

2 项目结构

我们先看 spring-kafka-demo模块的内容
在这里插入图片描述

3 application.yml 配置文件

主要指定集群信息、生产者信息、消费者信息。尤其重要的是序列化方式。

server:
  # 优雅停机
  shutdown: graceful

spring:
  kafka:
    # kafka集群信息,多个用逗号间隔
    bootstrap-servers: localhost:9092
    # 生产者
    producer:
      # 重试次数,设置大于0的值,则客户端会将发送失败的记录重新发送
      retries: 3
      #批量处理大小,16K
      batch-size: 16384
      #缓冲存储大,32M
      buffer-memory: 33554432
      acks: 1
      # 指定消息key和消息体的编码方式:字符串序列化
      key-serializer: org.apache.kafka.common.serialization.StringSerializer
      value-serializer: org.apache.kafka.common.serialization.StringSerializer
    # 消费者
    consumer:
      # 消费者组
      group-id: TestGroup
      # 是否自动提交
      enable-auto-commit: false
      # 消费偏移配置
      # none:如果没有为消费者找到先前的offset的值,即没有自动维护偏移量,也没有手动维护偏移量,则抛出异常
      # earliest:在各分区下有提交的offset时:从offset处开始消费;在各分区下无提交的offset时:从头开始消费
      # latest:在各分区下有提交的offset时:从offset处开始消费;在各分区下无提交的offset时:从最新的数据开始消费
      auto-offset-reset: latest
      # 指定消息key和消息体的解码方式:字符串反序列化
      key-deserializer: org.apache.kafka.common.serialization.StringDeserializer
      value-deserializer: org.apache.kafka.common.serialization.StringDeserializer
    # 监听
    listener:
      # record:当每一条记录被消费者监听器(ListenerConsumer)处理之后提交
      # batch:当每一批poll()的数据被ListenerConsumer处理之后提交
      # time:当每一批poll()的数据被ListenerConsumer处理之后,距离上次提交时间大于TIME时提交
      # count:当每一批poll()的数据被ListenerConsumer处理之后,被处理record数量大于等于COUNT时提交
      # count_time:TIME或COUNT中有一个条件满足时提交
      # manual:当每一批poll()的数据被ListenerConsumer处理之后, 手动调用Acknowledgment.acknowledge()后提交
      # manual_immediate:手动调用Acknowledgment.acknowledge()后立即提交,一般推荐使用这种
      ack-mode: manual_immediate

4 生产者 KafkaProducerComponent

package org.feng.kafka.sender;

import lombok.extern.slf4j.Slf4j;
import org.springframework.kafka.core.KafkaTemplate;
import org.springframework.kafka.support.SendResult;
import org.springframework.lang.NonNull;
import org.springframework.stereotype.Component;
import org.springframework.util.concurrent.ListenableFutureCallback;

import javax.annotation.Resource;

/**
 * Kafka消息生产者组件
 *
 * @version v1.0
 * @author: fengjinsong
 * @date: 2023年03月16日 23时26分
 */
@Slf4j
@Component
public class KafkaProducerComponent {

    @Resource
    private KafkaTemplate<String, String> kafkaTemplate;

    /**
     * 预先在 Kafka 中创建好的 topic
     */
    public static final String TOPIC = "testTopic";

    public void send(String topic, String data) {
        kafkaTemplate.send(topic, data)
                // 回调
                .addCallback(new ListenableFutureCallback<>() {
                    @Override
                    public void onFailure(@NonNull Throwable throwable) {
                        log.error("主题[{}]发送消息[{}]失败", topic, data, throwable);
                    }

                    @Override
                    public void onSuccess(SendResult<String, String> result) {
                        log.info("主题[{}]发送消息[{}]成功", topic, data);
                    }
                });
    }
}

5 消费者 KafkaConsumerComponent

package org.feng.kafka.receiver;

import lombok.extern.slf4j.Slf4j;
import org.feng.kafka.sender.KafkaProducerComponent;
import org.springframework.kafka.annotation.KafkaListener;
import org.springframework.stereotype.Component;

/**
 * 监听消息:消费端
 *
 * @version v1.0
 * @author: fengjinsong
 * @date: 2023年03月17日 19时54分
 */
@Slf4j
@Component
public class KafkaConsumerComponent {

    @KafkaListener(topics = KafkaProducerComponent.TOPIC)
    public void consumerTestTopic(String data) {
        log.info("消费者监听到数据:{}", data);
    }
}

6 控制器(GET请求发送消息)

package org.feng.kafka.controller;

import lombok.extern.slf4j.Slf4j;
import org.feng.kafka.sender.KafkaProducerComponent;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;

/**
 * 发送消息控制器
 *
 * @version v1.0
 * @author: fengjinsong
 * @date: 2023年03月17日 19时56分
 */
@Slf4j
@RestController
public class SendMessageController {

    @Resource
    private KafkaProducerComponent kafkaProducerComponent;

    @GetMapping("/send/{data}")
    public String send(@PathVariable("data") String data) {
        log.info("即将把数据【{}】发送到消息队列", data);
        kafkaProducerComponent.send(KafkaProducerComponent.TOPIC, data);
        return "send ok";
    }
}

7 启动类

package org.feng.kafka;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class SpringKafkaDemoApplication {

    public static void main(String[] args) {
        SpringApplication.run(SpringKafkaDemoApplication.class, args);
    }
}

8 测试效果

我这边已经启动了 Kafka ,随后在本地再启动本项目,待项目启动后,使用 GET 请求给 Kafka 中扔消息。
在这里插入图片描述
使用以上的链接触发。
可以依次观察到日志记录:

即将把数据【测试呢111】发送到消息队列
消费者监听到数据:测试呢111
主题[testTopic]发送消息[测试呢111]成功

写法二:发送复杂消息对象

其实就是自定义一个对象,直接扔到消息队列里。然后再使用监听器监听到,并作出处理。
核心改变的地方是消息Value 的序列化方式、反序列化方式,更改为:

在这里插入图片描述
修改了 group-id、值的序列化、反序列化,以及增加了属性“信任的包”。
你想把哪个类的对象放消息队列,就得在这个包下进行定义这个类。

1 创建项目

项目的版本和写法一保持一致。
包括 POM 文件也是一致的。

2 项目结构

在这里插入图片描述

3 application.yml 配置文件

PS:这里将注释几乎全部去掉了

server:
  shutdown: graceful
spring:
  kafka:
    bootstrap-servers: localhost:9092
    producer:
      retries: 3
      batch-size: 16384
      buffer-memory: 33554432
      acks: 1
      key-serializer: org.apache.kafka.common.serialization.StringSerializer
      # 值序列化:使用Json
      value-serializer: org.springframework.kafka.support.serializer.JsonSerializer
    consumer:
      group-id: TestObjectGroup
      enable-auto-commit: false
      auto-offset-reset: latest
      key-deserializer: org.apache.kafka.common.serialization.StringDeserializer
      # 值反序列化:使用Json
      value-deserializer: org.springframework.kafka.support.serializer.JsonDeserializer
      # 信任的包
      properties:
        spring:
          json:
            trusted:
              packages: org.feng.entity
    listener:
      ack-mode: manual_immediate

4 信任的包中定义的实体类

4.1 kafka 消息接口规则定义

package org.feng.entity;

/**
 * kafka 消息
 *
 * @version v1.0
 * @author: fengjinsong
 * @date: 2023年03月17日 20时16分
 */
public interface KafkaMessage {
}

4.2 测试实体定义

实体实现了 KafkaMessage 规则。
并定义了简单的属性值。

package org.feng.entity;

import lombok.Data;

import java.time.LocalDateTime;
import java.util.Locale;
import java.util.UUID;

/**
 * 测试kafka消息对象
 *
 * @version v1.0
 * @author: fengjinsong
 * @date: 2023年03月17日 20时18分
 */
@Data
public class TestKafkaMessage implements KafkaMessage {
    private LocalDateTime time = LocalDateTime.now();

    private String message;

    private String business = "test";

    private String messageId = UUID.randomUUID().toString().toLowerCase(Locale.ROOT).replaceAll("-", "");
}

5 生产者 KafkaObjectSerializerProducerComponent

package org.feng.producer;

import lombok.NonNull;
import lombok.extern.slf4j.Slf4j;
import org.feng.entity.KafkaMessage;
import org.springframework.kafka.core.KafkaTemplate;
import org.springframework.kafka.support.SendResult;
import org.springframework.stereotype.Component;
import org.springframework.util.concurrent.ListenableFutureCallback;

import javax.annotation.Resource;

/**
 * 生产者
 *
 * @version v1.0
 * @author: fengjinsong
 * @date: 2023年03月17日 20时21分
 */
@Slf4j
@Component
public class KafkaObjectSerializerProducerComponent {
    /**
     * 预先在 Kafka 中创建好的 topic
     */
    public static final String TOPIC = "testObjectTopic";

    @Resource
    private KafkaTemplate<String, ? super KafkaMessage> kafkaTemplate;

    public void sendTest(String topic, KafkaMessage kafkaMessage) {
        kafkaTemplate.send(topic, kafkaMessage)
                // 回调
                .addCallback(new ListenableFutureCallback<SendResult<String, ? super KafkaMessage>>() {
                    @Override
                    public void onFailure(@NonNull Throwable throwable) {
                        log.error("主题[{}]发送消息[{}]失败", topic, kafkaMessage, throwable);
                    }

                    @Override
                    public void onSuccess(SendResult<String, ? super KafkaMessage> result) {
                        log.info("主题[{}]发送消息[{}]成功,发送结果:{}", topic, kafkaMessage, result);
                    }
                });
    }
}

6 消费者 KafkaObjectSerializerConsumerComponent

package org.feng.consumer;

import lombok.extern.slf4j.Slf4j;
import org.feng.entity.TestKafkaMessage;
import org.feng.producer.KafkaObjectSerializerProducerComponent;
import org.springframework.kafka.annotation.KafkaListener;
import org.springframework.stereotype.Component;

/**
 * 消费者
 *
 * @version v1.0
 * @author: fengjinsong
 * @date: 2023年03月17日 20时30分
 */
@Component
@Slf4j
public class KafkaObjectSerializerConsumerComponent {

    @KafkaListener(topics = KafkaObjectSerializerProducerComponent.TOPIC)
    public void consumerTestTopic(TestKafkaMessage data) {
        log.info("消费者监听到数据:{}", data);
    }
}

7 控制器(GET请求发送消息)

重点在于,消息内容是自定义的 TestKafkaMessage 实例。

package org.feng.controller;

import lombok.extern.slf4j.Slf4j;
import org.feng.entity.TestKafkaMessage;
import org.feng.producer.KafkaObjectSerializerProducerComponent;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;

/**
 * 发送消息控制器
 *
 * @version v1.0
 * @author: fengjinsong
 * @date: 2023年03月17日 19时56分
 */
@Slf4j
@RestController
public class SendMessageController {

    @Resource
    private KafkaObjectSerializerProducerComponent kafkaObjectSerializerProducerComponent;

    @GetMapping("/send")
    public String send(@RequestBody TestKafkaMessage data) {
        log.info("即将把数据【{}】发送到消息队列", data);
        kafkaObjectSerializerProducerComponent.sendTest(KafkaObjectSerializerProducerComponent.TOPIC, data);
        return "send ok";
    }
}

8 启动类

和写法一基本一致(除了类名不同)

9 测试效果

我这边已经启动了 Kafka ,随后在本地再启动本项目,待项目启动后,使用 GET 请求给 Kafka 中扔消息。
在这里插入图片描述
使用以上的链接触发。
可以依次观察到日志记录:

即将把数据【TestKafkaMessage(time=2023-03-17T21:29:21.564849900, message=消息内容就是我了, business=test, messageId=aa12c2e29bed431090918d971477de16)】发送到消息队列
消费者监听到数据:TestKafkaMessage(time=2023-03-17T21:29:21.564849900, message=消息内容就是我了, business=test, messageId=aa12c2e29bed431090918d971477de16)
主题[testObjectTopic]发送消息[TestKafkaMessage(time=2023-03-17T21:29:21.564849900, message=消息内容就是我了, business=test, messageId=aa12c2e29bed431090918d971477de16)]成功,发送结果:SendResult [producerRecord=ProducerRecord(topic=testObjectTopic, partition=null, headers=RecordHeaders(headers = [RecordHeader(key = __TypeId__, value = [111, 114, 103, 46, 102, 101, 110, 103, 46, 101, 110, 116, 105, 116, 121, 46, 84, 101, 115, 116, 75, 97, 102, 107, 97, 77, 101, 115, 115, 97, 103, 101])], isReadOnly = true), key=null, value=TestKafkaMessage(time=2023-03-17T21:29:21.564849900, message=消息内容就是我了, business=test, messageId=aa12c2e29bed431090918d971477de16), timestamp=null), recordMetadata=testObjectTopic-0@1]

附录

1 减少日志输出

默认情况下,Kafka的日志很多都会打印出来,但是又与我们业务本身无关。需要屏蔽一下。
这里做了简单的处理,使用 logback 设置了日志级别。
在这里插入图片描述
logback 文件内容如下:

<?xml version="1.0" encoding="UTF-8" ?>
<configuration debug="false">
    <!-- 配置控制台输出 -->
    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <!-- 格式化输出: %d表示日期, %thread表示线程名, %-5level: 级别从左显示5个字符宽度 %msg:日志消息, %n是换行符 -->
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS}[%thread] %-5level %logger{50} - %msg%n</pattern>
        </encoder>
    </appender>

    <!-- 日志输出级别 -->
    <root level="INFO">
        <appender-ref ref="STDOUT"/>
    </root>
    <!-- 定制化某些包的日志输出级别 -->
    <logger name="org.apache.kafka" level="warn" additivity="false"/>
    <logger name="org.springframework" level="info">
        <appender-ref ref="STDOUT" />
    </logger>
</configuration>

效果如下:
在这里插入图片描述
发现日志确实少了很多。这样也方便我们后续开发。

2 手动提交偏移量

细心的朋友们可能已经发现了,以上的实例中,在项目重新启动时,会自动消费几条数据,这主要是因为我们设置了“不自动提交偏移量”,但是程序中又没有去手动提交
现在我们来处理这个问题,首先是对原先的配置进行微调:

server:
  shutdown: graceful
spring:
  kafka:
    bootstrap-servers: localhost:9092
    producer:
      retries: 3
      batch-size: 16384
      buffer-memory: 33554432
      acks: 1
      key-serializer: org.apache.kafka.common.serialization.StringSerializer
      value-serializer: org.springframework.kafka.support.serializer.JsonSerializer
    consumer:
      group-id: TestObjectGroup
      # 依然使用非自动提交
      enable-auto-commit: false
      # 修改读取的偏移量的方式
      auto-offset-reset: earliest
      key-deserializer: org.apache.kafka.common.serialization.StringDeserializer
      value-deserializer: org.springframework.kafka.support.serializer.JsonDeserializer
      properties:
        spring:
          json:
            trusted:
              packages: org.feng.entity
    listener:
      ack-mode: manual
      # 设置并发量
      concurrency: 3

以上修改了读取偏移量的方式为:在各分区下有提交的offset时,从offset处开始消费;在各分区下无提交的offset时:从头开始消费
然后调整监听者的配置 ack-mode: manual,当每一批poll()的数据被消费端处理之后, 手动调用Acknowledgment.acknowledge()后提交。
监听器的写法上也做一下调整:

package org.feng.consumer;

import lombok.extern.slf4j.Slf4j;
import org.apache.kafka.clients.consumer.ConsumerRecord;
import org.feng.entity.TestKafkaMessage;
import org.feng.producer.KafkaObjectSerializerProducerComponent;
import org.springframework.kafka.annotation.KafkaListener;
import org.springframework.kafka.support.Acknowledgment;
import org.springframework.stereotype.Component;

/**
 * 消费者
 *
 * @version v1.0
 * @author: fengjinsong
 * @date: 2023年03月17日 20时30分
 */
@Component
@Slf4j
public class KafkaObjectSerializerConsumerComponent {
    
    @KafkaListener(topics = KafkaObjectSerializerProducerComponent.TOPIC)
    public void consumeTestTopicAndCommit(ConsumerRecord<String, TestKafkaMessage> record, Acknowledgment ack) {
        try {
            log.info("消费者监听到数据:{}", record.value());
            // 手动提交
            ack.acknowledge();
        } catch (Exception e) {
            log.info("消费失败,数据:{}", record.value(), e);
        }
    }
}

监听器的主要调整在于方法入参、消费者处理消息后增加手动提交的操作。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【C++】多态

文章目录多态的概念多态的定义及实现多态的构成条件虚函数虚函数的重写C11 final和override抽象类概念多态的原理&#xff08;以下演示在32平台&#xff09;虚函数表多态的原理静态绑定和动态绑定单继承和多继承关系的虚函数表单继承派生类的虚函数表多继承派生类的虚函数表其他…

彻底理解Session、Cookie、Token,入门及实战

文章目录Session Cookie的使用Token的使用Session Cookie的使用 1. Session存储数据 HttpSession session request.getSession(); //Servlet底层通过的SESSIONID&#xff0c;获取Session对象。 session.setAttribute("loginTime",new Date()); out.println(&q…

【算法基础】数据结构| 单链表+双链表 代码实现+图解+原理

博主简介&#xff1a;努力学习的预备程序媛一枚~博主主页&#xff1a; 是瑶瑶子啦所属专栏: Java岛冒险记【从小白到大佬之路】 前言 因为瑶瑶子正在备战蓝桥杯和校内ACM选拔赛&#xff0c;最近在学习算法相关的知识。我是借助AcWing网站来学习的&#xff0c;这篇文章是我学习…

1.3 K8S入门之组件说明

Borg K8S起源于Borg系统三种请求来源&#xff1a; borgcfgCLTWEB browsersBorgMaster: 负责请求的分发Borglet: 工人sheduler&#xff1a;包工头 和Persist store交互&#xff0c;不直接和Borglet交互Borglet监听Persist store K8S CS结构 Master服务器Node节点 Replicat…

行业洞察丨PDF图纸为什么影响生产企业的生产质量?订单交期?

随着现代社会科技的发展&#xff0c;在全球激烈的市场竞争下&#xff0c;国内企业基于质量和成本的竞争已经日益转化为基于时间的竞争&#xff0c;如何快速响应瞬息万变的市场需求&#xff0c;更快完成生产订单交付&#xff1f;这已成为生产型企业面临的一大痛点。 承接市场客户…

python搭建web服务器

前言&#xff1a;相信看到这篇文章的小伙伴都或多或少有一些编程基础&#xff0c;懂得一些linux的基本命令了吧&#xff0c;本篇文章将带领大家服务器如何部署一个使用django框架开发的一个网站进行云服务器端的部署。 文章使用到的的工具 Python&#xff1a;一种编程语言&…

用 DolphinDB 和 Python Celery 搭建一个高性能因子计算平台

因子挖掘是量化金融研究和交易的核心工作。传统的开发流程中&#xff0c;通常使用 Python 从关系型数据库&#xff08;如 SqlServer, Oracle 等&#xff09;读取数据&#xff0c;在 Python 中进行因子计算。随着证券交易规模不断扩大以及交易数据量的激增&#xff0c;用户对因子…

QT VTK开发 (一、下载编译)

Vtk&#xff0c;&#xff08;visualization toolkit&#xff09;是一个开源的免费软件系统&#xff0c;主要用于三维计算机图形学、图像处理和可视化。Vtk是在面向对象原理的基础上设计和实现的&#xff0c;它的内核是用C构建的&#xff0c;包含有大约250,000行代码&#xff0c…

计算机组成原理实验一(完整)

在VC中使用调试功能将下列语句运行的内存存放结果截图&#xff0c;每运行一句需截图一次。 #include<stdio.h> int main() {int a 你的学号末两位-100; //0x&#xff1f;&#xff1f;&#xff1f;&#xff1f;&#xff1f;&#xff1f;&#xff1f;&#xff1f;&#x…

关于Anaconda的下载和安装方法及报错说明

初学者接触python时&#xff0c;常会因各种环境问题、各种包的安装问题而苦恼&#xff0c;Anaconda则可以解决这一切繁琐的问题&#xff0c;但很多人不知道如何下载安装配置&#xff0c;本文详细讲述下载和安装配置过程&#xff0c;也汇总常见安装过程中的错误&#xff08;零基…

【3】核心易中期刊推荐——人工智能计算机仿真

🚀🚀🚀NEW!!!核心易中期刊推荐栏目来啦 ~ 📚🍀 核心期刊在国内的应用范围非常广,核心期刊发表论文是国内很多作者晋升的硬性要求,并且在国内属于顶尖论文发表,具有很高的学术价值。在中文核心目录体系中,权威代表有CSSCI、CSCD和北大核心。其中,中文期刊的数…

【Kubernetes】第二十八篇 - 实现自动构建部署

一&#xff0c;前言 上一篇&#xff0c;介绍了 Deployment、Service 的创建&#xff0c;完成了前端项目的构建部署&#xff1b; 希望实现&#xff1a;推送代码 -> 自动构建部署-> k8s 滚动更新&#xff1b; 本篇&#xff0c;实现自动构建部署 二&#xff0c;推送触发构…

28个案例问题分析---15---登陆之后我加入的课程调用接口报错--ArrayList线程不安全。占用内存情况

ArrayList线程不安全。占用内存情况故事背景方案&思路解决线程不安全的问题方案一&#xff1a;在这两个方法之前添加 synchronized 关键字。方案二&#xff1a;使用ThreadLocal变量。解决重复创建对象问题。总结&升华故事背景 存入redis的值&#xff0c;可能会出现错误…

黑马《数据结构与算法2023版》正式发布

有人的地方就有江湖。 在“程序开发”的江湖之中&#xff0c;各种技术流派风起云涌&#xff0c;变幻莫测&#xff0c;每一位IT侠客&#xff0c;对“技术秘籍”的追求和探索也从未停止过。 要论开发技术哪家强&#xff0c;可谓众说纷纭。但长久以来&#xff0c;确有一技&#…

实用调试技巧【详细介绍】

实用调试技巧1. 什么是bug&#xff1f;2. 调试是什么&#xff1f;有多重要&#xff1f;2.1 调试是什么&#xff1f;2.2 调试的基本步骤2.3 Debug和Release的介绍3. Windows环境调试介绍3.1 调试环境的准备3.2 学会快捷键3.3 调试的时候查看程序当前信息3.3.1 查看临时变量的值3…

Java中的异常

程序错误一般分为三种&#xff1a;编译错误&#xff1a; 编写程序时没有遵循语法规则&#xff0c;编译程序能够自己发现错误并提示位置和原因。运行错误&#xff1a;程序在执行的时候运行环境发现了不能执行的操作。比如&#xff0c;JVM出错了&#xff0c;内存溢出等。逻辑错误…

Docker常用项目实战演练

docker镜像源的修改 linux环境下编辑 /etc/docker/daemon.json vi /etc/docker/daemon.json #如添加如下网易镜像源 { "registry-mirrors": ["http://hub-mirror.c.163.com"] }docker run命令详细解释 日常工作中用的比较多的是docker run命令&#xff…

2023年目标检测毕业设计(yolov5车辆识别、车辆检测、车牌识别、行人识别)

车辆识别视频yolov5车辆识别视频yolov5 yoloR对比行人车辆识别视频yolov8识别视频订阅专栏获得源码:http://t.csdn.cn/zsG47 ​​​​​​​先看一下yolo发展史 二、单目测距原理 图中有一个车辆&#xff0c;且车辆在地面上&#xff0c;其接地点Q必定在地面上。那么Q点的深度便…

少儿Python每日一题(23):楼梯问题

原题解答 本次的题目如下所示&#xff1a; 楼梯有n阶台阶&#xff0c;上楼可以一步上1阶&#xff0c;也可以一步上2阶&#xff0c;走完n阶台阶共有多少种不同的走法&#xff1f; 输入格式&#xff1a; 输入楼梯的阶梯数n 输出格式&#xff1a; 输出不同走法的个数 输入样例&am…

Unity学习日记12(导航走路相关、动作完成度返回参数)

目录 动作的曲线与函数 创建遮罩 导航走路 设置导航网格权重 动作的曲线与函数 执行动作&#xff0c;根据动作完成度返回参数。 函数&#xff0c;在代码内执行同名函数即可调用。在执行关键帧时调用。 创建遮罩 绿色为可效用位置 将其运用到Animator上的遮罩&#xff0c;可…
最新文章