说明:本项目为springboot+kafak的整合项目,故其用了springboot中对kafak的消费注解@KafkaListener
首先,application.properties中配置用逗号隔开的多个topic。
方法:利用Spring的SpEl表达式,将topics 配置为:@KafkaListener(topics = “#{’${topics}’.split(’,’)}”)
运行程序,console打印的效果如下:
因为只开了一条消费者线程,所以所有的topic和分区都分配给这条线程。
如果你想开多条消费者线程去消费这些topic,添加@KafkaListener注解的参数concurrency的值为自己想要的消费者个数即可(注意,消费者数要小于等于你开的所有topic的分区数总和)
运行程序,console打印的效果如下:
总结一下大家问的最多的一个问题:
如何在程序运行的过程中,改变topic,消费者能够消费修改后的topic?
ans:经过尝试,使用@KafkaListener注解实现不了此需求,在程序启动的时候,程序就会根据@KafkaListener的注解信息初始化好消费者去消费指定好的topic。如果在程序运行的过程中,修改topic,不会让此消费者修改消费者的配置再重新订阅topic的。
不过我们可以有个折中的办法,就是利用@KafkaListener的topicPattern参数来进行topic匹配。
具体如何操作的可以看下这位老哥的blog:
https://blog.csdn.net/songzehao/article/details/103091486
终极方法:
思路:
不使用@KafkaListener,使用kafka客户端依赖,手动初始化消费者,开启消费者线程。在消费者线程中,每次循环都从配置、数据库或者其他配置源获取最新的topic信息,与之前的topic比较,如果发生变化,重新订阅topic或者初始化消费者。
实现
加入kafka客户端依赖(本次测试服务端kafka版本:2.12-2.4.0)
org.apache.kafka	kafka-clients	2.3.0
代码
@Service @Slf4j public class KafkaConsumers implements InitializingBean { /** * 消费者 */ private static KafkaConsumerconsumer; /** * topic */ private ListtopicList; public static String getNewTopic() { try { return org.apache.commons.io.FileUtils.readLines(new File("D:/topic.txt"), "utf-8").get(0); } catch (IOException e) { e.printStackTrace(); } return null; } /** * 初始化消费者(配置写死是为了快速测试,请大家使用配置文件) * * @param topicList * @return */ public KafkaConsumergetInitConsumer(ListtopicList) { //配置信息 Properties props = new Properties(); //kafka服务器地址 props.put("bootstrap.servers", "192.168.9.185:9092"); //必须指定消费者组 props.put("group.id", "haha"); //设置数据key和value的序列化处理类 props.put("key.deserializer", StringDeserializer.class); props.put("value.deserializer", StringDeserializer.class); //创建消息者实例 KafkaConsumerconsumer = new KafkaConsumer