spring kafka使用(三)

传送门:
spring kafka使用(一)
spring kafka使用(二)

本篇文章只介绍接收方

手动提交

kafka在配置文件中可以配置手动提交还是自动提交
将enable-auto-commit 改为false
添加listener.ack-mode= MANUAL_IMMEDIATE

  kafka:
    bootstrap-servers: 192.168.2.91:9090,192.168.2.91:9091,192.168.2.91:9092 # 集群的地址
	consumer:
      group-id: default
      enable-auto-commit: false  # 自动提交
      auto-commit-interval: 100 # 自动提交次数
      auto-offset-reset: earliest   #当默认的消费组启动的时候,会从默认的第一个消费组开始消费。
      key-deserializer: org.apache.kafka.common.serialization.StringDeserializer
      value-deserializer: org.apache.kafka.common.serialization.StringDeserializer
    listener:
      #        RECORD, 每条记录被监听
      #        BATCH, 批量
      #        TIME,
      #        COUNT,
      #        COUNT_TIME,
      #        MANUAL, 手动通知
      #        MANUAL_IMMEDIATE; 立即手动通知
      ack-mode: MANUAL_IMMEDIATE

在这里插入图片描述
文件KafkaReceiver中的消息接收,新增Acknowledgment 接收字段
在这里插入图片描述

 @KafkaListener(id = "rollback_default_test", topics = {"topic.quick.default"})
    public void receiveSk(ConsumerRecord<String, String> record, Acknowledgment ack) {
        System.out.println(record);
        System.out.println("我收到了普通消息");
        // 手动确认消息被 消费
        ack.acknowledge();
        // ack.nack(1000); 拒收当前消息,并睡眠10秒钟后再重新接收消息
        // ack.nack(100,1000); 拒收当前消息,并睡眠10秒钟后接收第100条之后的消息
    }

在这里插入图片描述

异常处理

创建ErrorListener
在这里插入图片描述

package com.kofan.server.kafkaMq.component;

import org.springframework.context.annotation.Bean;
import org.springframework.kafka.listener.ConsumerAwareListenerErrorHandler;
import org.springframework.kafka.support.KafkaHeaders;
import org.springframework.messaging.MessageHeaders;
import org.springframework.stereotype.Component;

import java.util.List;


/**
 * @author king
 * 异常处理,该消息会被接受,防止消息被需要放置在别的地方
 */
@Component
public class ErrorListener {


    @Bean
    public ConsumerAwareListenerErrorHandler listenerErrorHandler() {
        return (message, e, consumer) -> {
            MessageHeaders headers = message.getHeaders();
           /*  // 批量时获取值
            List<String> topics = headers.get(KafkaHeaders.RECEIVED_TOPIC, List.class);
            List<Integer> partitions = headers.get(KafkaHeaders.RECEIVED_PARTITION_ID, List.class);
            List<Long> offsets = headers.get(KafkaHeaders.OFFSET, List.class);*/
            System.out.println(message);
            System.out.println(e);
            System.out.println(consumer);
            return null;
        };
    }
}

接收消息
在接收消息KafkaListener里添加 errorHandler = “listenerErrorHandler”
listenerErrorHandler就是ErrorListener文件中的异常处理方法名

    @KafkaListener(id = "rollback_default_test", topics = {"topic.quick.default"}, errorHandler = "listenerErrorHandler")
    public void receiveSk(ConsumerRecord<String, String> record, Acknowledgment ack) {
        System.out.println(record);
        System.out.println("我收到了普通消息");
        ack.acknowledge();
//         ack.nack(1000);
    }

注意! 创建异常方法之后,如果接收方法报错,但是该条信息还是被消费了,需要在异常方法中额外记录该消息,否则该消息可能丢失

如果没有该异常方法,则该KafkaListener会一直接收当前消息,并一直报错

消息转发

消息转发只需方法@SendTo指向topic即可

 @KafkaListener(id = "rollback_test", topics = {"topic.quick.default"})
    @SendTo("topic.quick.initial")
    public Object receiveSkMessageInfo(ConsumerRecord<String, String> record, @Header(KafkaHeaders.RECEIVED_TOPIC) String topic, Acknowledgment ack) {
        System.out.println(record);
        System.out.println(topic);
        System.out.println(ack);
        ack.acknowledge();
        return record.value();
    

批量接收

在其他老版本,基本上百度搜到的都是需要创建消费工厂
现在已经不需要了,都2202年了,创建什么工厂?spring-kafka已经帮你创建了,只需要配置就可以了
配置文件:
设置max-poll-records=500,一次最多拉500条消息,设置listener.ack-mode= MANUAL,设置listener.type = batch

kafka:
    bootstrap-servers: 192.168.2.91:9090,192.168.2.91:9091,192.168.2.91:9092 # 集群的地址
    consumer:
      group-id: default
      enable-auto-commit: true  # 自动提交
      auto-commit-interval: 100 # 自动提交次数
      auto-offset-reset: earliest   #当默认的消费组启动的时候,会从默认的第一个消费组开始消费。
      key-deserializer: org.apache.kafka.common.serialization.StringDeserializer
      value-deserializer: org.apache.kafka.common.serialization.StringDeserializer
      max-poll-records: 500  #一次最多拉500条消息。
    listener:
      #        RECORD, 每条记录被监听
      #        BATCH, 批量
      #        TIME,
      #        COUNT,
      #        COUNT_TIME,
      #        MANUAL, 手动通知
      #        MANUAL_IMMEDIATE; 立即手动通知
      ack-mode: MANUAL
      # batch 批量 single 单一
      type: batch

在这里插入图片描述
这样就可以接受批量消息了
接收方:

    /**
     * 批量消费
     * 手动提交的时候,默认是自动提交的,报错会自动回滚
     * @param records
     * @param ack
     */
    @KafkaListener(id = "rollback_default_test", topics = {"topic.quick.default"})
    public void receiveS(List<ConsumerRecord> records, Acknowledgment ack) {
        System.out.println(records);
        System.out.println("我收到了批量消息");
        System.out.println(ack);
        ack.acknowledge();
    }

注意:批量消费的时候,项目中不能出现单一消费,单一消费的时候不能出现批量消费。批量消费的时候手动提交状态影响的只是是否拒收消息,如果不出现报错,就算没有 ack.acknowledge();该批消息依然是被消费了 。

指定分区

KafkaListener监听指定区的消息

/**
     * 监听指定分区的消息
     * <p>
     * TopicPartition: 消息分区,partitions:指定区
     * partitionOffsets:偏移量,partitionOffsets偏移组,partition指定一个区,initialOffset偏移量
     * 例: 当前的为:1. 鉴定0,1两个区,
     * 		2. 监听2,3两个区,并设置2号区从第100条以后开始
     */
@KafkaListener(id = "rollback_default_test", topicPartitions = {
            @TopicPartition(topic = "topic.quick.default", partitions = {"0", "1"}),
            @TopicPartition(topic = "", partitions = {"2", "3"}, partitionOffsets = {
                    @PartitionOffset(partition = "2", initialOffset = "100")}
            )
    })
    public void receiveZ(List<ConsumerRecord> records, Acknowledgment ack) {
        System.out.println(records);
        System.out.println("我收到了批量消息");
        System.out.println(ack);
        ack.acknowledge();
    }

定时接收

package com.kofan.server.kafkaMq.component;

import org.springframework.kafka.config.KafkaListenerEndpointRegistry;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;

/**
 * @author king
 */

@Component
@EnableScheduling
public class KafkaListenerComponent {
    @Resource
    private KafkaListenerEndpointRegistry endpointRegistry;
    //定时器,开启kafka监听
    @Scheduled(cron = "0 45 10 * * ?")
    public void startListener() {
        //判断监听容器是否启动,未启动则将其启动
        if (!endpointRegistry.getListenerContainer("rollback_default_test").isRunning()) {
            endpointRegistry.getListenerContainer("rollback_default_test").start();
        }
        endpointRegistry.getListenerContainer("rollback_default_test").resume();
    }
    //定时器,关闭kafka监听
    @Scheduled(cron = "0 50 10 * * ?")
    public void shutDownListener() {
        endpointRegistry.getListenerContainer("rollback_default_test").pause();
    }
}

修改KafkaTopicConfig
在这里插入图片描述
将代码添加进KafkaTopicConfig

    @Resource
    private ConsumerFactory consumerFactory;
    @Bean
    public ConcurrentKafkaListenerContainerFactory delayContainerFactory() {
        ConcurrentKafkaListenerContainerFactory container = new ConcurrentKafkaListenerContainerFactory();
        container.setConsumerFactory(consumerFactory);
        //禁止自动启动
        container.setAutoStartup(false);
        return container;
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

vace cc

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值