首先得自己搭建一個kafka,搭建教程請自行百度,本人是使用docker搭建了一個單機版的zookeeper+kafka作為演示,文末會有完整程式碼包提供給大家下載參考
廢話不多說,教程開始
一、老規矩,先在pom.xml中新增kafka相關依賴
<dependency>
<groupId>org.springframework.kafka</groupId>
<artifactId>spring-kafka</artifactId>
</dependency>
二、在application.yml中新增相關配置
spring:
#kafka配置
kafka:
#這裡改為你的kafka伺服器ip和埠號
bootstrap-servers: 10.24.19.237:9092
#=============== producer =======================
producer:
#如果該值大於零時,表示啟用重試失敗的傳送次數
retries: 0
#每當多個記錄被髮送到同一分割槽時,生產者將嘗試將記錄一起批量處理為更少的請求,預設值為16384(單位位元組)
batch-size: 16384
#生產者可用於緩衝等待傳送到伺服器的記錄的記憶體總位元組數,預設值為3355443
buffer-memory: 33554432
#key的Serializer類,實現類實現了介面org.apache.kafka.common.serialization.Serializer
key-serializer: org.apache.kafka.common.serialization.StringSerializer
#value的Serializer類,實現類實現了介面org.apache.kafka.common.serialization.Serializer
value-serializer: org.apache.kafka.common.serialization.StringSerializer
#=============== consumer =======================
consumer:
#用於標識此使用者所屬的使用者組的唯一字串
group-id: test-consumer-group
#當Kafka中沒有初始偏移量或者伺服器上不再存在當前偏移量時該怎麼辦,預設值為latest,表示自動將偏移重置為最新的偏移量
#可選的值為latest, earliest, none
auto-offset-reset: earliest
#消費者的偏移量將在後臺定期提交,預設值為true
enable-auto-commit: true
#如果'enable-auto-commit'為true,則消費者偏移自動提交給Kafka的頻率(以毫秒為單位),預設值為5000。
auto-commit-interval: 100
#金鑰的反序列化器類,實現類實現了介面org.apache.kafka.common.serialization.Deserializer
key-deserializer: org.apache.kafka.common.serialization.StringDeserializer
#值的反序列化器類,實現類實現了介面org.apache.kafka.common.serialization.Deserializer
value-deserializer: org.apache.kafka.common.serialization.StringDeserializer
三、新增操作kafka的工具類KafkaUtils.java(這裡我只是簡單的封裝了一些方法,大家可以根據需要自行新增需要的方法)
package com.example.study.util;
import com.google.common.collect.Lists;
import org.apache.kafka.clients.admin.*;
import org.apache.kafka.common.TopicPartitionInfo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.kafka.core.KafkaTemplate;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors;
/**
* 操作kafka的工具類
*
* @author 154594742@qq.com
* @date 2021/3/2 14:52
*/
@Component
public class KafkaUtils {
@Value("${spring.kafka.bootstrap-servers}")
private String springKafkaBootstrapServers;
private AdminClient adminClient;
@Autowired
private KafkaTemplate kafkaTemplate;
/**
* 初始化AdminClient
* '@PostConstruct該註解被用來修飾一個非靜態的void()方法。
* 被@PostConstruct修飾的方法會在伺服器載入Servlet的時候執行,並且只會被伺服器執行一次。
* PostConstruct在建構函式之後執行,init()方法之前執行。
*/
@PostConstruct
private void initAdminClient() {
Map<String, Object> props = new HashMap<>(1);
props.put(AdminClientConfig.BOOTSTRAP_SERVERS_CONFIG, springKafkaBootstrapServers);
adminClient = KafkaAdminClient.create(props);
}
/**
* 新增topic,支援批量
*/
public void createTopic(Collection<NewTopic> newTopics) {
adminClient.createTopics(newTopics);
}
/**
* 刪除topic,支援批量
*/
public void deleteTopic(Collection<String> topics) {
adminClient.deleteTopics(topics);
}
/**
* 獲取指定topic的資訊
*/
public String getTopicInfo(Collection<String> topics) {
AtomicReference<String> info = new AtomicReference<>("");
try {
adminClient.describeTopics(topics).all().get().forEach((topic, description) -> {
for (TopicPartitionInfo partition : description.partitions()) {
info.set(info + partition.toString() + "\n");
}
});
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
return info.get();
}
/**
* 獲取全部topic
*/
public List<String> getAllTopic() {
try {
return adminClient.listTopics().listings().get().stream().map(TopicListing::name).collect(Collectors.toList());
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
return Lists.newArrayList();
}
/**
* 往topic中傳送訊息
*/
public void sendMessage(String topic, String message) {
kafkaTemplate.send(topic, message);
}
}
四、新增KafkaController.java作為kafka的demo類
package com.example.study.controller;
import com.example.study.model.vo.ResponseVo;
import com.example.study.util.BuildResponseUtils;
import com.example.study.util.KafkaUtils;
import com.google.common.collect.Lists;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.apache.kafka.clients.admin.NewTopic;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.kafka.annotation.KafkaListener;
import org.springframework.web.bind.annotation.*;
import java.util.List;
/**
* kafka控制器
*
* @author 154594742@qq.com
* @date 2021/3/2 15:01
*/
@RestController
@Api(tags = "Kafka控制器")
@Slf4j
public class KafkaController {
@Autowired
private KafkaUtils kafkaUtils;
/**
* 新增topic (支援批量,這裡就單個作為演示)
*
* @param topic topic
* @return ResponseVo
*/
@ApiOperation("新增topic")
@PostMapping("kafka")
public ResponseVo<?> add(String topic) {
NewTopic newTopic = new NewTopic(topic, 3, (short) 1);
kafkaUtils.createTopic(Lists.newArrayList(newTopic));
return BuildResponseUtils.success();
}
/**
* 查詢topic資訊 (支援批量,這裡就單個作為演示)
*
* @param topic 自增主鍵
* @return ResponseVo
*/
@ApiOperation("查詢topic資訊")
@GetMapping("kafka/{topic}")
public ResponseVo<String> getBytTopic(@PathVariable String topic) {
return BuildResponseUtils.buildResponse(kafkaUtils.getTopicInfo(Lists.newArrayList(topic)));
}
/**
* 刪除topic (支援批量,這裡就單個作為演示)
* (注意:如果topic正在被監聽會給人感覺刪除不掉(但其實是刪除掉後又會被建立))
*
* @param topic topic
* @return ResponseVo
*/
@ApiOperation("刪除topic")
@DeleteMapping("kafka/{topic}")
public ResponseVo<?> delete(@PathVariable String topic) {
kafkaUtils.deleteTopic(Lists.newArrayList(topic));
return BuildResponseUtils.success();
}
/**
* 查詢所有topic
*
* @return ResponseVo
*/
@ApiOperation("查詢所有topic")
@GetMapping("kafka/allTopic")
public ResponseVo<List<String>> getAllTopic() {
return BuildResponseUtils.buildResponse(kafkaUtils.getAllTopic());
}
/**
* 生產者往topic中傳送訊息demo
*
* @param topic
* @param message
* @return
*/
@ApiOperation("往topic傳送訊息")
@PostMapping("kafka/message")
public ResponseVo<?> sendMessage(String topic, String message) {
kafkaUtils.sendMessage(topic, message);
return BuildResponseUtils.success();
}
/**
* 消費者示例demo
* <p>
* 基於註解監聽多個topic,消費topic中訊息
* (注意:如果監聽的topic不存在則會自動建立)
*/
@KafkaListener(topics = {"topic1", "topic2", "topic3"})
public void consume(String message) {
log.info("receive msg: " + message);
}
}
五、執行專案,然後訪問 http://localhost:8080/swagger-ui.html 測試一下效果吧
這三個topic本來是不存在的,這裡是由@KafkaListener註解方式監聽時自動建立的
1、我們來新增一個名為‘myTopic’的topic試試
2、再重新查詢一下所有的topic發現我們新增topic成功了
3、接下來我們試試刪除一下myTopic和由@KafkaListener註解方式監聽時自動建立的topic1