Kafka 入门实战(3)--SpringBoot 整合 Kafka

spring-kafka 使得在 Spring 环境中使用 Kafka 变的很简单,只需少量的配置和少量的代码就可以发送和接受消息了。本文主要介绍在 SpringBoot 中用 spring-kafka 操作 Kafka,文中使用到的软件版本:Kafka 2.8.0、SpringBoot 2.4.6、Java 1.8.0_191。

1、参数说明

spring-kafka 中参数是以 spring.kafka 开头的,后面的参数名称和 Kafka 的原始参数很类似,只不过 spring-kafka 会把一些参数中的 "." 改为 "-",如 auto.offset.reset 改为 spring.kafka.consumer.auto-offset-reset。

前缀 描述
spring.kafka Spring 中 Kafka 相关配置总的前缀
spring.kafka.consumer 消费者相关参数
spring.kafka.producer  生产者相关参数
spring.kafka.admin Kafka 管理相关参数

kafka 的原始参数说明可参考:Kafka入门实战(1)-概念、安装及简单使用;或参考官方文档

2、SpringBoot 整合 Kafka

2.1、引入依赖

<dependency>
    <groupId>org.springframework.kafka</groupId>
    <artifactId>spring-kafka</artifactId>
</dependency>
<!--流处理需要用到-->
<dependency>
    <groupId>org.apache.kafka</groupId>
    <artifactId>kafka-streams</artifactId>
</dependency>

2.2、增加 Kafka 配置

spring:
  kafka:
    bootstrap-servers: 10.49.196.10:9092
    producer:
      acks: all
      transaction-id-prefix: tx. #开启事务,发送消息的方法需增加@Transactional注解
      key-serializer: org.apache.kafka.common.serialization.StringSerializer
      value-serializer: org.apache.kafka.common.serialization.StringSerializer
    consumer:
      group-id: groupA
      auto-offset-reset:
    streams:
      application-id: streams-test
      properties:
        "[default.key.serde]": org.apache.kafka.common.serialization.Serdes$StringSerde
        "[default.value.serde]": org.apache.kafka.common.serialization.Serdes$StringSerde

2.3、发送消息

package com.abc.demo.kafka;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.kafka.core.KafkaTemplate;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

@Component
public class Producer {
    @Autowired
    private KafkaTemplate<String, String> kafkaTemplate;

    @Transactional
    @Scheduled(cron = "0/10 * * * * ?")
    public void sendMessage() {
        for (int i = 0; i < 10; i++) {
            kafkaTemplate.send("test", "消息" + i);
        }
    }

//    @Scheduled(cron = "0/10 * * * * ?")
//    public void sendMessage2() {
//        kafkaTemplate.executeInTransaction(new KafkaOperations.OperationsCallback(){
//            @Override
//            public Object doInOperations(KafkaOperations kafkaOperations) {
//                for (int i = 0; i < 10; i++) {
//                    kafkaTemplate.send("test", "消息" + i);
//                }
//                return null;
//            }
//        });
//    }
}

2.4、接受消息

package com.abc.demo.kafka;

import org.apache.kafka.clients.consumer.ConsumerRecord;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.kafka.annotation.KafkaListener;
import org.springframework.stereotype.Component;

@Component
public class Consumer {
    private static Logger logger = LoggerFactory.getLogger(Consumer.class);

    @KafkaListener(topics = "test")
    public void recevieMessage(ConsumerRecord<String, String> record) {
        logger.info("offset={}, key={}, value={}", record.offset(), record.key(), record.value());
    }
}

2.5、流处理

package com.abc.demo.kafka;

import org.apache.kafka.common.serialization.Serdes;
import org.apache.kafka.streams.KeyValue;
import org.apache.kafka.streams.StreamsBuilder;
import org.apache.kafka.streams.kstream.KStream;
import org.apache.kafka.streams.kstream.Produced;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.kafka.annotation.EnableKafkaStreams;
import org.springframework.kafka.support.serializer.JsonSerde;

import java.util.HashMap;
import java.util.Map;

@Configuration(proxyBeanMethods = false)
@EnableKafkaStreams
public class StreamConfig {
    @Bean
    public KStream<String, String> kStream(StreamsBuilder streamsBuilder) {
        KStream<String, String> stream = streamsBuilder.stream("stream-in");
        //从 stream-in 队列中读取数据,处理后发送给 stream-out 队列
        //发送数据 key,value 分别使用的序列化类为Serdes.String(),JsonSerde
        stream.map(this::uppercaseValue).to("stream-out", Produced.with(Serdes.String(), new JsonSerde<>()));
        return stream;
    }

    /**
     * 消息转换,新的消息:key-原来的value值,value-一个map
     */
    private KeyValue<String, Map> uppercaseValue(String key, String value) {
        Map<String, String> map = new HashMap<>();
        map.put("message", value.toUpperCase());
        map.put("timestamp", System.currentTimeMillis() + "");
        return new KeyValue(value, map);
    }
}

程序从 stream-in 中读取消息,对消息加工后再发送给 stream-out;打开两个终端,一个往 stream-in 发送消息,一个接受 stream-out 的消息。

./kafka-console-producer.sh --broker-list 10.49.196.10:9092 --topic stream-in #发送消息

./kafka-console-consumer.sh --bootstrap-server 10.49.196.10:9092 --topic stream-out --property print.key=true #接受消息

stream-in 的输入:

stream-out 的输出:

 

posted @ 2021-07-24 11:14  且行且码  阅读(1231)  评论(0编辑  收藏  举报