1.pom.xml中引入最新kafka版本:
<!-- https://mvnrepository.com/artifact/org.springframework.kafka/spring-kafka -->
<dependency>
<groupId>org.springframework.kafka</groupId>
<artifactId>spring-kafka</artifactId>
<version>3.3.3</version>
</dependency>
2.application.properties中配置kafka:
## kafka ##
spring.kafka.bootstrap-servers=127.0.0.1:9092
spring.kafka.producer.key-serializer=org.apache.kafka.common.serialization.StringSerializer
spring.kafka.producer.value-serializer=org.apache.kafka.common.serialization.StringSerializer
spring.kafka.consumer.group-id=test
spring.kafka.consumer.enable-auto-commit=true
spring.kafka.consumer.key-deserializer=org.apache.kafka.common.serialization.StringDeserializer
spring.kafka.consumer.value-deserializer=org.apache.kafka.common.serialization.StringDeserializer
kafka.topic.name=yzh
默认懒加载,服务启动时不会生效,只有在第一次使用kafka生产、消费数据时才会加载生效。
3.kafka消息生产者:
import com.alibaba.fastjson2.JSON;
import jakarta.annotation.PostConstruct;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.kafka.core.KafkaTemplate;
import org.springframework.kafka.support.SendResult;
import org.springframework.stereotype.Component;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
/**
* kafka生产者
*
* @author yangzihe
* @date 2025/2/21
*/
@Component
@Slf4j
public class KafkaProducer {
private static KafkaTemplate<String, Object> kafkaTemplateStatic;
@Resource
private KafkaTemplate<String, Object> kafkaTemplate;
@PostConstruct
public void init() {
kafkaTemplateStatic = kafkaTemplate;
}
/**
* 同步发送kafka消息
*/
public static void send(String topic, Object message) {
try {
SendResult<String, Object> result = kafkaTemplateStatic.send(topic, JSON.toJSONString(message)).get(1000, TimeUnit.MILLISECONDS);
log.info("kafka同步发送消息成功, result={}", result.getProducerRecord());
} catch (InterruptedException e) {
log.error("kafka同步发送消息异常!topic={}, message={}", topic, message, e);
Thread.currentThread().interrupt();
throw new RuntimeException("kafka同步发送消息异常");
} catch (ExecutionException | TimeoutException e) {
log.error("kafka同步发送消息异常!topic={}, message={}", topic, message, e);
throw new RuntimeException("kafka同步发送消息异常");
}
}
/**
* 异步发送kafka消息
*/
public static void asyncSend(String topic, Object message) {
CompletableFuture<SendResult<String, Object>> future = kafkaTemplateStatic.send(topic, JSON.toJSONString(message));
future.whenComplete((result, e) -> {
if (e == null) {
log.info("kafka异步发送消息成功, result={}", result.getProducerRecord());
} else {
// 异常处理
log.error("kafka异步发送消息异常!topic={}, message={}", topic, message, e);
}
});
}
}
发送消息的方法封装成了 static 静态方法,只是为了方便业务调用!注意:KafkaTemplate还是依赖于spring容器的。
4.kafka消息消费者:
import lombok.extern.slf4j.Slf4j;
import org.apache.kafka.clients.consumer.ConsumerRecord;
import org.springframework.kafka.annotation.KafkaListener;
import org.springframework.stereotype.Component;
/**
* kafka消费者
*/
@Component
@Slf4j
public class KafkaConsumer {
@KafkaListener(topics = "${kafka.topic.name}", groupId = "test")
public void listen(ConsumerRecord<?, ?> record) {
log.info("topic={}, partition={}, offset={}, message={}", record.topic(), record.partition(), record.offset(), record.value());
}
// 二选一即可
@KafkaListener(topics = "${kafka.topic.name}", groupId = "test2")
public void listen(String message) {
log.info("message={}", message);
}
}
5.启动类测试:
import com.pxb7.mall.app.infrastructure.kafka.KafkaProducer;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
@SpringBootApplication
public class Application2 {
public static void main(String[] args) {
SpringApplication.run(Application2.class, args);
}
// 使用CommandLineRunner接口执行代码
@Bean
public CommandLineRunner run() {
return args -> {
// 执行启动后的操作
for (int i = 0; i < 10; i++) {
KafkaProducer.send("yzh", "消息" + i);
}
};
}
}
消费日志:
配置参数补充:
#acks = 0 如果设置为零,则生产者将不会等待来自服务器的任何确认,该记录将立即添加到套接字缓冲区并视为已发送。在这种情况下,无法保证服务器已收到记录,并且重试配置将不会生效(因为客户端通常不会知道任何故障),为每条记录返回的偏移量始终设置为-1。
#acks = 1 这意味着leader会将记录写入其本地日志,但无需等待所有副本服务器的完全确认即可做出回应,在这种情况下,如果leader在确认记录后立即失败,但在将数据复制到所有的副本服务器之前,则记录将会丢失。
#acks = all 这意味着leader将等待完整的同步副本集以确认记录,这保证了只要至少一个同步副本服务器仍然存活,记录就不会丢失,这是最强有力的保证,这相当于acks = -1的设置。
#可以设置的值为:all, -1, 0, 1
spring.kafka.producer.acks=1
#该值大于零时,表示启用重试失败的发送次数
spring.kafka.producer.retries=3