第二章 Spring Boot 整合 Kafka消息队列 生产者
系列文章目录
第一章 Kafka 配置部署及SASL_PLAINTEXT安全认证
第二章 Spring Boot 整合 Kafka消息队列 生产者
第三章 Spring Boot 整合 Kafka消息队列 消息者(待续)
前言
Kafka 是一个消息队列产品,基于Topic partitions的设计,能达到非常高的消息发送处理性能。本文主是基于Spirng Boot封装了Apache 的Kafka-client,用于在Spring Boot 项目里快速集成kafka。
一、Kafka 是什么?
Apache Kafka是分布式发布-订阅消息系统。
它最初由LinkedIn公司开发,之后成为Apache项目的一部分。
Kafka是一种快速、可扩展的、设计内在就是分布式的,分区的和可复制的提交日志服务。
二、生产者
1.引入库
引入需要依赖的jar包,引入POM文件
<dependencies>
<dependency>
<groupId>org.springframework.kafka</groupId>
<artifactId>spring-kafka</artifactId>
</dependency>
</dependencies>
2.配置文件
spring:
custom:
kafka:
username: admin
password: admin-secret
partitions: 1
enable-auto-commit: false
batch-listener: false
bootstrap-servers:
- 192.168.1.95:9092
3.端启动类
启动类名 EnableAutoKafka
package com.cdkjframework.kafka.producer.annotation; import com.cdkjframework.kafka.producer.config.KafkaMarkerConfiguration;
import org.springframework.context.annotation.Import; import java.lang.annotation.*; /**
* @ProjectName: cdkj-framework
* @Package: com.cdkjframework.kafka.producer.annotation
* @ClassName: EnableAutoKafka
* @Description: Kafka自动启动类
* @Author: xiaLin
* @Date: 2023/7/18 9:20
* @Version: 1.0
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import({KafkaMarkerConfiguration.class})
public @interface EnableAutoKafka {
}
4.spring.factories配置文件
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.cdkjframework.kafka.producer.config.KafkaAutoConfiguration
5.配置类
5.1 kafka 配置 KafkaConfig
package com.cdkjframework.kafka.producer.config; import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration; import java.util.List; /**
* @ProjectName: cdkj-framework
* @Package: com.cdkjframework.kafka.producer.config;
* @ClassName: KafakConfig
* @Description: Kafak 配置
* @Author: xiaLin
* @Version: 1.0
*/
@Data
@Configuration
@ConfigurationProperties(prefix = "spring.custom.kafka")
public class KafkaConfig { /**
* 服务列表
*/
private List<String> bootstrapServers; /**
* 主题
*/
private List<String> topics; /**
* 账号
*/
private String username; /**
* 密码
*/
private String password; /**
* 延迟为1毫秒
*/
private Integer linger = 1; /**
* 批量大小
*/
private Integer batchSize = 16384; /**
* 重试次数,0为不启用重试机制
*/
private Integer retries = 0; /**
* 人锁
*/
private Integer maxBlock = 6000; /**
* acks
*/
private String acks = "1"; /**
* security.providers
*/
private String securityProviders; /**
* 启用自动提交
*/
private boolean enableAutoCommit = true; /**
* 会话超时
*/
private String sessionTimeout = "5000"; /**
* 会话超时
*/
private Integer maxPollInterval = 10000; /**
* 组ID
*/
private String groupId = "defaultGroup"; /**
* 最大投票记录
*/
private Integer maxPollRecords = 1; /**
* 并发性
*/
private Integer concurrency = 3; /**
* 拉取超时时间
*/
private Integer pollTimeout = 60000; /**
* 批量监听
*/
private boolean batchListener = false; /**
* 副本数量
*/
private String sort = "1"; /**
* 分区数
*/
private Integer partitions = 3; /**
* 消费者默认支持解压
*/
private String compressionType = "none"; /**
* offset偏移量规则设置
*/
private String autoOffsetReset = "earliest"; /**
* 自动提交的频率
*/
private Integer autoCommitInterval = 100; /**
* 生产者可以使用的总内存字节来缓冲等待发送到服务器的记录
*/
private Integer bufferMemory = 33554432; /**
* 消息的最大大小限制
*/
private Integer maxRequestSize = 1048576;
}
5.2 kafka 自动配置 KafkaAutoConfiguration
package com.cdkjframework.kafka.producer.config; import com.cdkjframework.kafka.producer.ProducerConfiguration;
import com.cdkjframework.kafka.producer.util.ProducerUtils;
import lombok.RequiredArgsConstructor;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.ImportAutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.web.reactive.function.client.WebClientAutoConfiguration;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Lazy; /**
* @ProjectName: cdkj-framework
* @Package: com.cdkjframework.kafka.producer.config
* @ClassName: KafkaAutoConfiguration
* @Description: kafka 自动配置
* @Author: xiaLin
* @Date: 2023/7/18 9:21
* @Version: 1.0
*/
@Lazy(false)
@RequiredArgsConstructor
@Configuration(proxyBeanMethods = false)
@EnableConfigurationProperties(KafkaConfig.class)
@AutoConfigureAfter({WebClientAutoConfiguration.class})
@ImportAutoConfiguration(ProducerConfiguration.class)
@ConditionalOnBean(KafkaMarkerConfiguration.Marker.class)
public class KafkaAutoConfiguration { /**
* 读取配置文件
*/
private final KafkaConfig kafkaConfig; /**
* kafka topic 启动触发器
*
* @return 返回结果
*/
@Bean(initMethod = "kafkaAdmin")
@ConditionalOnMissingBean
public TopicConfig kafkaTopic() {
TopicConfig trigger = new TopicConfig(kafkaConfig);
return trigger;
} /**
* kafka 配置 启动触发器
*
* @return 返回结果
*/
@Bean(initMethod = "start")
@ConditionalOnMissingBean
public ProducerUtils Producer() {
return new ProducerUtils();
}
}
5.3 kafka 标记配置 KafkaMarkerConfiguration
package com.cdkjframework.kafka.producer.config; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.kafka.annotation.EnableKafka; /**
* @ProjectName: cdkj-framework
* @Package: com.cdkjframework.kafka.producer.config
* @ClassName: KafkaMarkerConfiguration
* @Description: Kafka标记配置
* @Author: xiaLin
* @Date: 2023/12/6 9:45
* @Version: 1.0
*/
@EnableKafka
@Configuration(proxyBeanMethods = false)
public class KafkaMarkerConfiguration { @Bean
public Marker kafkaMarker() {
return new Marker();
} public static class Marker { }
}
5.4 topic配置 TopicConfig
package com.cdkjframework.kafka.producer.config; import com.cdkjframework.constant.IntegerConsts;
import org.apache.kafka.clients.admin.AdminClientConfig;
import org.apache.kafka.clients.admin.NewTopic;
import org.springframework.kafka.core.KafkaAdmin; import java.util.HashMap;
import java.util.Map; /**
* @ProjectName: cdkj-framework
* @Package: com.cdkjframework.kafka.producer.config
* @ClassName: TopicConfig
* @Description: topic配置
* @Author: xiaLin
* @Version: 1.0
*/
public class TopicConfig { /**
* 配置
*/
private final KafkaConfig kafkaConfig; /**
* 构造函数
*/
public TopicConfig(KafkaConfig kafkaConfig) {
this.kafkaConfig = kafkaConfig;
} /**
* 定义一个KafkaAdmin的bean,可以自动检测集群中是否存在topic,不存在则创建
*/
public KafkaAdmin kafkaAdmin() {
Map<String, Object> configs = new HashMap<>(IntegerConsts.ONE);
// 指定多个kafka集群多个地址,例如:192.168.2.11,9092,192.168.2.12:9092,192.168.2.13:9092
configs.put(AdminClientConfig.BOOTSTRAP_SERVERS_CONFIG, kafkaConfig.getBootstrapServers());
configs.put(AdminClientConfig.BOOTSTRAP_SERVERS_CONFIG, kafkaConfig.getBootstrapServers());
return new KafkaAdmin(configs);
}
}
6.生产者配置
生产者配置类 ProducerConfiguration
package com.cdkjframework.kafka.producer; import com.cdkjframework.kafka.producer.config.KafkaConfig;
import com.cdkjframework.kafka.producer.util.ProducerUtils;
import com.cdkjframework.util.tool.StringUtils;
import lombok.RequiredArgsConstructor;
import org.apache.kafka.clients.CommonClientConfigs;
import org.apache.kafka.clients.producer.ProducerConfig;
import org.apache.kafka.common.config.SaslConfigs;
import org.apache.kafka.common.security.auth.SecurityProtocol;
import org.apache.kafka.common.serialization.StringSerializer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.kafka.core.DefaultKafkaProducerFactory;
import org.springframework.kafka.core.KafkaTemplate;
import org.springframework.kafka.core.ProducerFactory; import javax.annotation.Resource;
import java.util.HashMap;
import java.util.Map; /**
* @ProjectName: cdkj-framework
* @Package: com.cdkjframework.kafka.producer
* @ClassName: ProducerConfiguration
* @Description: 设置@Configuration、@EnableKafka两个注解,声明Config并且打开KafkaTemplate能力。
* @Author: xiaLin
* @Version: 1.0
*/
@Configuration
@RequiredArgsConstructor
public class ProducerConfiguration { /**
* 配置
*/
private final KafkaConfig kafkaConfig; /**
* JAAS配置
*/
private String JAAS_CONFIG = "org.apache.kafka.common.security.plain.PlainLoginModule required username=%s password=%s;"; /**
* Producer Template 配置
*/
@Bean(name = "kafkaTemplate")
public KafkaTemplate<String, String> kafkaTemplate() {
return new KafkaTemplate<>(producerFactory());
} /**
* Producer 工厂配置
*/
@Bean(name = "producerFactory")
public ProducerFactory<String, String> producerFactory() {
return new DefaultKafkaProducerFactory<>(producerConfigs());
} /**
* Producer 参数配置
*/
public Map<String, Object> producerConfigs() {
Map<String, Object> props = new HashMap<>();
// 指定多个kafka集群多个地址
props.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, kafkaConfig.getBootstrapServers()); // 重试次数,0为不启用重试机制
props.put(ProducerConfig.RETRIES_CONFIG, kafkaConfig.getRetries());
//同步到副本, 默认为1
// acks=0 把消息发送到kafka就认为发送成功
// acks=1 把消息发送到kafka leader分区,并且写入磁盘就认为发送成功
// acks=all 把消息发送到kafka leader分区,并且leader分区的副本follower对消息进行了同步就任务发送成功
props.put(ProducerConfig.ACKS_CONFIG, kafkaConfig.getAcks()); // 生产者空间不足时,send()被阻塞的时间,默认60s
props.put(ProducerConfig.MAX_BLOCK_MS_CONFIG, kafkaConfig.getMaxBlock());
// security.providers
props.put(ProducerConfig.SECURITY_PROVIDERS_CONFIG, kafkaConfig.getSecurityProviders());
// 控制批处理大小,单位为字节
props.put(ProducerConfig.BATCH_SIZE_CONFIG, kafkaConfig.getBatchSize());
// 批量发送,延迟为1毫秒,启用该功能能有效减少生产者发送消息次数,从而提高并发量
props.put(ProducerConfig.LINGER_MS_CONFIG, kafkaConfig.getLinger());
// 生产者可以使用的总内存字节来缓冲等待发送到服务器的记录
props.put(ProducerConfig.BUFFER_MEMORY_CONFIG, kafkaConfig.getBufferMemory());
// 消息的最大大小限制,也就是说send的消息大小不能超过这个限制, 默认1048576(1MB)
props.put(ProducerConfig.MAX_REQUEST_SIZE_CONFIG, kafkaConfig.getMaxRequestSize());
// 键的序列化方式
props.put(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, StringSerializer.class);
// 值的序列化方式
props.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, StringSerializer.class);
// 压缩消息,支持四种类型,分别为:none、lz4、gzip、snappy,默认为none。
// 消费者默认支持解压,所以压缩设置在生产者,消费者无需设置。
props.put(ProducerConfig.COMPRESSION_TYPE_CONFIG, kafkaConfig.getCompressionType());
props.put(ProducerConfig.MAX_IN_FLIGHT_REQUESTS_PER_CONNECTION, kafkaConfig.getPartitions()); // 账号密码
if (StringUtils.isNotNullAndEmpty(kafkaConfig.getUsername()) &&
StringUtils.isNotNullAndEmpty(kafkaConfig.getPassword())) {
props.put(CommonClientConfigs.SECURITY_PROTOCOL_CONFIG, SecurityProtocol.SASL_PLAINTEXT.name);
String SASL_MECHANISM = "PLAIN";
props.put(SaslConfigs.SASL_MECHANISM, SASL_MECHANISM);
props.put(SaslConfigs.SASL_JAAS_CONFIG, String.format(JAAS_CONFIG, kafkaConfig.getUsername(), kafkaConfig.getPassword()));
} return props;
} }
7. 生产者工具
生产者端 ProducerUtils
package com.cdkjframework.kafka.producer.util; import com.cdkjframework.constant.IntegerConsts;
import com.cdkjframework.util.log.LogUtils;
import org.springframework.kafka.core.KafkaTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.concurrent.ListenableFutureCallback; import javax.annotation.Resource;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException; /**
* @ProjectName: cdkj-framework
* @Package: com.cdkjframework.kafka.producer.util
* @ClassName: ProducerUtils
* @Description: 生产工具
* @Author: xiaLin
* @Version: 1.0
*/ public class ProducerUtils { /**
* 日志
*/
private static LogUtils logUtils = LogUtils.getLogger(ProducerUtils.class); /**
* 模板
*/
private static KafkaTemplate kafkaTemplate; /**
* 数据模板
*/
@Resource(name = "kafkaTemplate")
private KafkaTemplate template; /**
* 初始化工具
*/
private void start() {
kafkaTemplate = template;
} /**
* producer 同步方式发送数据
*
* @param topic topic名称
* @param message producer发送的数据
* @throws InterruptedException 异常信息
* @throws ExecutionException 异常信息
* @throws TimeoutException 异常信息
*/
public static void sendMessageSync(String topic, String message) throws InterruptedException, ExecutionException, TimeoutException {
kafkaTemplate.send(topic, message).get(IntegerConsts.TEN, TimeUnit.SECONDS);
} /**
* producer 异步方式发送数据
*
* @param topic topic名称
* @param message producer发送的数据
*/
public static void sendMessageAsync(String topic, String message) {
kafkaTemplate.send(topic, message).addCallback(new ListenableFutureCallback() {
@Override
public void onFailure(Throwable throwable) {
logUtils.error("topic:" + topic + ",message:" + message);
logUtils.error(throwable, throwable.getMessage());
} @Override
public void onSuccess(Object o) {
logUtils.info("topic:" + topic + ",发送成功");
}
});
} /**
* producer 异步方式发送数据
*
* @param topic topic名称
* @param key key值
* @param message producer发送的数据
*/
public static void sendMessageAsync(String topic, String key, String message) {
kafkaTemplate.send(topic, key, message).addCallback(new ListenableFutureCallback() {
@Override
public void onFailure(Throwable throwable) {
logUtils.error("topic:" + topic + ",message:" + message);
logUtils.error(throwable, throwable.getMessage());
} @Override
public void onSuccess(Object o) {
logUtils.info("topic:" + topic + ",发送成功");
}
});
}
}

总结
例如:以上就是今天要讲的内容,本文仅仅简单介绍了 Spring Boot 集成消息生产者的封装,消息者待续。
相对应的开源项目欢迎访问:维基框架
第二章 Spring Boot 整合 Kafka消息队列 生产者的更多相关文章
- Spring Boot 整合 Kafka
Kafka 环境搭建 kafka 安装.配置.启动.测试说明: 1. 安装:直接官网下载安装包,解压到指定位置即可(kafka 依赖的 Zookeeper 在文件中已包含) 下载地址:https:// ...
- Spring Kafka和Spring Boot整合实现消息发送与消费简单案例
本文主要分享下Spring Boot和Spring Kafka如何配置整合,实现发送和接收来自Spring Kafka的消息. 先前我已经分享了Kafka的基本介绍与集群环境搭建方法.关于Kafka的 ...
- spring boot整合kafka
最近项目需求用到了kafka信息中间件,在此做一次简单的记录,方便以后其它项目用到. 引入依赖 <dependency> <groupId>org.springframewor ...
- spring boot 2.x 系列 —— spring boot 整合 kafka
文章目录 一.kafka的相关概念: 1.主题和分区 2.分区复制 3. 生产者 4. 消费者 5.broker和集群 二.项目说明 1.1 项目结构说明 1.2 主要依赖 二. 整合 kafka 2 ...
- Spring Boot (25) RabbitMQ消息队列
MQ全程(Message Queue)又名消息队列,是一种异步通讯的中间件.可以理解为邮局,发送者将消息投递到邮局,然后邮局帮我们发送给具体的接收者,具体发送过程和时间与我们无关,常见的MQ又kafk ...
- Netty学习第四章 spring boot整合netty的使用
现在大多数项目都是基于spring boot进行开发,所以我们以spring boot作为开发框架来使用netty.使用spring boot的一个好处就是能给将netty的业务拆分出来,并通过spr ...
- Kafka:Springboot整合Kafka消息队列
本文主要分享下Spring Boot和Spring Kafka如何配置整合,实现发送和接收来自Spring Kafka的消息. 项目结构 pom依赖包 <?xml version="1 ...
- kafka学习(五)Spring Boot 整合 Kafka
文章更新时间:2020/06/08 一.创建Spring boot 工程 创建过程不再描述,创建后的工程结构如下: POM文件中要加入几个依赖: <?xml version="1.0& ...
- java并发学习--第二章 spring boot实现线程的创建
除了之前介绍的创建线程方式外,spring boot为我们了提供一套完整的线程创建方式,其中包括了:线程.线程池.线程的监控. 一.使用spring boot提供的方法创建线程与线程池 1.首先在sp ...
- Spring Boot 之 RabbitMQ 消息队列中间件的三种模式
开门见山(文末附有消息队列的几个基本概念) 1.直接模式( Direct)模式 直白的说就是一对一,生产者对应唯一的消费者(当然同一个消费者可以开启多个服务). 虽然使用了自带的交换器(Exchang ...
随机推荐
- Luogu P1784 数独 [ 模板 ] / P1074 靶形数独 题解 [ 蓝 ] [ 深搜 ] [ 剪枝 ] [ 卡常 ]
数独模板 , 靶形数独 卡了 2h ,再也不想写数独了. 普通数独 思路 显然是对每个格子进行枚举,类似八皇后的方法去做,朴素方法是由 \((1,1)\) 到 \((9,9)\) 遍历过去. 优化 我 ...
- 从龟速乘到 $Miller-Rabin$ 算法(数论算法总结)
发现自己竟然菜到不太会龟速乘,所以把 \(Miller-Rabin\) 算法所需要用到的算法全学了一遍-- 龟速乘 龟速乘是一种 \(O(\log n)\) 的乘法计算方法. 考虑有时普通乘法取模会爆 ...
- Redis 大 Key 分析利器:支持 TOP N、批量分析与从节点优先
背景 Redis 大 key 分析工具主要分为两类: 1. 离线分析 基于 RDB 文件进行解析,常用工具是 redis-rdb-tools(https://github.com/sripathikr ...
- go语言实现终端里的倒计时
最近在更新系统的时候发现pacman的命令行界面变了,我有很久没更新过设备上的Linux系统了,所以啥时候变的不好说.但这一变化成功勾起了我的好奇心.新版的更新进度界面如下: 新的更新进度界面能同时显 ...
- MySQL索引最左原则:从原理到实战的深度解析
MySQL索引最左原则:从原理到实战的深度解析 一.什么是索引最左原则? 索引最左原则是MySQL复合索引使用的核心规则,简单来说: "当使用复合索引(多列索引)时,查询条件必须从索引的最左 ...
- CICFlowMeter 使用方法
前言 因实验需要提取流量特征,就找到了这个较为著名的流量特征提取工具 CICFlowMeter .例如 CIC-IDS-2017 数据集就是通过这个工具提取而来. 网络上的教程众说纷纭,但我始终是无法 ...
- Web前端入门第 5 问:写一个 Hello, World! 踹开程序开发的大门
创建一个文件夹,并打开文件夹,在文件夹中创建一个 5.txt 文件,双击打开记事本编辑. 输入 Hello, World! , Ctrl + s 保存. 修改文件名为 5.html . 打开浏览器,将 ...
- Golang 入门 : 整型
整型介绍 Go语言同时提供了有符号和无符号类型的整数运算.这里有 int8.int16.int32 和 int64 四种截然不同大小的有符号整形数类型,分别对应 8.16.32.64 bit大小的有符 ...
- go module基本使用
前提 go版本为1.13及以上 官方文档 如果你想更深层次的了解GO MODULE的意义及开发者们的顾虑,可以直接访问官方文档(EN) https://github.com/golang/go/wik ...
- websocket 后台新订单通知 —— Laravel 5.8 workman PHPSocket.IO教程
websocket 后台新订单通知 -- Laravel 5.8 Laravel-echo-server教程 PHPSocket.IO,PHP跨平台实时通讯框架 PHPSocket.IO是PHP版本的 ...