spring+kafka的KafkaTemplate使用

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
 

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值