Spring-Kafka(學習筆記2020.3.24)

Spring-Kafka(學習筆記2020.3.24)

前言:

Spring-Kafka是將核心Spring概念應用於基於Kafka的消息傳遞解決方案的開發。它提供了一個“模板”作爲發送消息的高級抽象。它還爲帶有@KafkaListener註釋和“偵聽器容器”的消息驅動的POJO提供支持。這些庫促進了依賴注入和聲明式的使用。

簡單明瞭,叫是進行封裝了複雜的操作,提供模板方式簡化了操作方式,使用起來更加簡單。

特徵

  • KafkaTemplate
  • KafkaMessageListenerContainer
  • @KafkaListener
  • KafkaTransactionManager
  • spring-kafka-test 嵌入式kafka服務器的jar

先前條件:您必須安裝並運行Apache Kafka

1. 快速入門

xml方式

1.1 引入依賴:

 <dependencies>
       <!--   spring-kafka依賴    -->
       <dependency>
           <groupId>org.springframework.kafka</groupId>
           <artifactId>spring-kafka</artifactId>
           <version>2.4.4.RELEASE</version>
       </dependency>
   </dependencies>

使用Spring Boot時,忽略版本,Boot將自動引入與您的Boot版本兼容的正確版本

生產者配置

1.2 編寫生產者Producer配置文件

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
         http://www.springframework.org/schema/beans/spring-beans.xsd
         http://www.springframework.org/schema/context
         http://www.springframework.org/schema/context/spring-context.xsd">

    <!-- 1.定義producer的參數 -->
    <bean id="producerProperties" class="java.util.HashMap">
        <constructor-arg>
            <map>
                <!--  brokers 地址-->
                <entry key="bootstrap.servers" value="localhost:9092" />
                <!--   組id 生產者是什麼分組, 消費者也要是相同  -->
                <entry key="group.id" value="mykafka" />
                <!--  發送失敗重試次數  -->
                <entry key="retries" value="1" />
                <!-- 批處理條數:  -->
                <entry key="batch.size" value="16384" />
                <!--批處理延遲時間上限:即1ms過後,不管是否達到批處理數,都直接發送一次請求   -->
                <entry key="linger.ms" value="1" />
                <!-- 即32MB的批處理緩衝區 -->
                <entry key="buffer.memory" value="33554432" />
                <!-- 即所有副本都同步到數據時send方法才返回, 以此來完全判斷數據是否發送成功, 理論上來講數據不會丟失           -->
                <entry key="acks" value="all" />
                <entry key="key.serializer"
                       value="org.apache.kafka.common.serialization.StringSerializer" />
                <entry key="value.serializer"
                       value="org.apache.kafka.common.serialization.StringSerializer" />
            </map>
        </constructor-arg>
    </bean>

    <!-- 2.創建kafkatemplate需要使用的producerfactory bean -->
    <bean id="producerFactory"
          class="org.springframework.kafka.core.DefaultKafkaProducerFactory">
        <!-- 使用參數初始化工廠 -->
        <constructor-arg>
            <ref bean="producerProperties" />
        </constructor-arg>
    </bean>

    <!-- 3.創建kafkatemplate bean,使用的時候,只需要注入這個bean,即可使用template的send消息方法 -->
    <bean id="KafkaTemplate" class="org.springframework.kafka.core.KafkaTemplate">
        <constructor-arg ref="producerFactory" />
        <constructor-arg name="autoFlush" value="true" />
        <property name="defaultTopic" value="defaultTopic" />
        <!-- 發送信息返回的結果進行監聽 可選 -->
        <property name="producerListener" ref="MyProducerListener"/>
    </bean>

    <!-- 4.我的生產者監聽類  監聽發送結果 - 可選 -->
    <bean id="MyProducerListener" class="com.zhihao.resultlistener.KafkaProducerListener"/>
</beans>

1.3 生產者監聽類

監聽發送結果的KafkaProducerListener

public class KafkaProducerListener implements ProducerListener<String,String> {

    @Override
    public void onSuccess(ProducerRecord<String, String> producerRecord, RecordMetadata recordMetadata) {
        System.out.println("發送成功了"+producerRecord.value());
    }

    @Override
    public void onError(ProducerRecord<String, String> producerRecord, Exception exception) {
        System.out.println("發送失敗了"+producerRecord.value());
        System.out.println("發送失敗了"+exception.getMessage());
    }
}

消費者配置

1.4 編寫消費者Consumer配置文件

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
     http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
     http://www.springframework.org/schema/tx
     http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
     http://www.springframework.org/schema/jee
     http://www.springframework.org/schema/jee/spring-jee-3.0.xsd
     http://www.springframework.org/schema/context
      http://www.springframework.org/schema/context/spring-context-3.0.xsd">


    <!-- 1.定義consumer的參數 -->
    <bean id="consumerProperties" class="java.util.HashMap">
        <constructor-arg>
            <map>
                <entry key="bootstrap.servers" value="localhost:9092"/>
                <!--   組id 生產者是什麼分組, 消費者也要是相同  -->
                <entry key="group.id" value="mykafka"/>
                <!--   啓用自動提交     -->
                <entry key="enable.auto.commit" value="true"/>
                <!--   自動提交間隔  -->
                <entry key="auto.commit.interval.ms" value="1000"/>
                <!--   在使用Kafka的組管理時,用於檢測消費者故障的超時  -->
                <entry key="session.timeout.ms" value="15000"/>
                <entry key="key.deserializer" value="org.apache.kafka.common.serialization.StringDeserializer"/>
                <entry key="value.deserializer" value="org.apache.kafka.common.serialization.StringDeserializer"/>
            </map>
        </constructor-arg>
    </bean>

    <!-- 2.創建consumerFactory bean -->
    <bean id="consumerFactory" class="org.springframework.kafka.core.DefaultKafkaConsumerFactory">
        <constructor-arg>
            <ref bean="consumerProperties"/>
        </constructor-arg>
    </bean>

    <!-- 3.我的實際執行消息消費的類 -->
    <bean id="MyMessageListenerConsumerService" class="com.zhihao.KafkaConsumerServer"/>

    <!-- 4.消費者容器屬性配置 -->
    <bean id="MyConsumerContainerConfig" class="org.springframework.kafka.listener.ContainerProperties">
        <!-- 訂閱 mykafkaDemo 主題(topic) -->
        <constructor-arg value="mykafkaDemo"/>
        <!--  選擇我的監聽類進行消費   -->
        <property name="messageListener" ref="MyMessageListenerConsumerService"/>
    </bean>

   <!-- 5.創建多線程Kafka消息監聽容器,執行doStart()方法 -->
    <!-- consumerFactory+containerProperties -> messageListenerContainer 容器配置(topics)+ 消息監聽器,構造一個併發消息監聽容器,並執行初始化方法doStart -->
    <bean id="messageListenerContainer" class="org.springframework.kafka.listener.ConcurrentMessageListenerContainer" init-method="doStart" >
        <constructor-arg ref="consumerFactory" />
        <constructor-arg ref="MyConsumerContainerConfig" />
         <!-- 併發數 -->
        <property name="concurrency" value="5" />
    </bean>
    
    <!-- 創建單線程Kafka消息監聽器容器 -->
<!--    <bean id="MyConsumerMessageListenerContainer" class="org.springframework.kafka.listener.KafkaMessageListenerContainer"-->
<!--          init-method="doStart">-->
<!--        <constructor-arg ref="consumerFactory"/>-->
<!--        <constructor-arg ref="MyConsumerContainerConfig"/>-->
<!--    </bean>-->

</beans>

1.5 消費者監聽類

MessageListener接口實現時,當消費者拉取消息之後,消費完成會自動提交offset,即enable.auto.commit爲true時

public class KafkaConsumerServer implements MessageListener<String, String> {

    /**
     * 接收消息後自動提交offset 需要配置開啓enable-auto-commit: true
     *
     * @param message
     * @return void
     * @author: zhihao
     * @date: 2020/3/23
     */
    @Override
    public void onMessage(ConsumerRecord<String, String> message) {
        String topic = message.topic();
        System.out.println(topic);
        System.out.println("--------topic1--------");
        System.out.println(message.key());
        System.out.println("---------key1-------");
        System.out.println(message.value());
    }
}

1.6 進行測試

@RunWith(value = SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {"classpath:spring-kafka-producer.xml","classpath:spring-kafka-consumer.xml"})
public class SpringKafka {

    @Autowired
    private KafkaTemplate<String,String> kafkaTemplate;

    @Test
    public void sendMessage() throws InterruptedException {
        ListenableFuture<SendResult<String, String>> mykafkaDemo = null;
        for (int i = 0; i < 100; i++) {
            mykafkaDemo = kafkaTemplate.send("mykafkaDemo", "name" + i, "love" + i);
        }
        
        //可選添加回調,而不使用監聽類
        //mykafkaDemo.addCallback();
        Thread.sleep(5000);
    }
 }   

1.7 手動提交消費者監聽類

使用AcknowledgeMessageListener時,當消費者消費一條消息之後,不會自動提交offset,需要手動ack,即enable.auto.commit爲false時,適合使用此接口

如果業務較重,且offset自動提交時,出現消費異常或者消費失敗的情況,消費者容易丟失消息,所以需要採用手動提交offset的方式。

先在消費者配置文件屬性中關閉自動提交:

<!--   啓用自動提交     -->
<entry key="enable.auto.commit" value="false"/>
 <!-- 在 4.消費者容器屬性配置 加上屬性-->
<property name="ackMode" value="MANUAL_IMMEDIATE"/>
/**
 * @Author: zhihao
 * @Date: 2020/3/23 16:05
 * @Description: 實現的是確認消息監聽器
 * @Versions 1.0
 **/
public class KafkaConsumerServer implements AcknowledgingMessageListener<String, String> {


    /**
     * 接收消息手動提交
     *
     * @param message
     * @param acknowledgment
     * @return void
     * @author: zhihao
     * @date: 2020/3/23
     */
    @Override
    public void onMessage(ConsumerRecord<String, String> message, Acknowledgment acknowledgment) {
        String topic = message.topic();
        System.out.println(topic);
        System.out.println("--------topic--------");
        System.out.println(message.key());
        System.out.println("---------key-------");
        System.out.println(message.value());
        //最終提交確認接收到消息  手動提交 offset
        acknowledgment.acknowledge();
    }

屬性說明

  • RECORD >>>每處理一條commit一次
  • BATCH(默認) >>> 每次poll的時候批量提交一次,頻率取決於每次poll的調用頻率
  • TIME>>>每次間隔ackTime的時間去commit
  • COUNT>>>累積達到ackCount次的ack去commit
  • COUNT_TIME >>> ackTime或ackCount哪個條件先滿足,就commit
  • MANUAL >>> listener負責ack,但是背後也是批量上去
  • MANUAL_IMMEDIATE >>> listner負責ack,每調用一次,就立即commit

2. 註解方式

使用註解方式, 並設置成功消費的迴應!

2.1 引入依賴

 	<!--   spring-kafka依賴    -->
       <dependency>
           <groupId>org.springframework.kafka</groupId>
           <artifactId>spring-kafka</artifactId>
           <version>2.4.4.RELEASE</version>
       </dependency>

使用Spring Boot時,忽略版本,Boot將自動引入與您的Boot版本兼容的正確版本

2.2編寫生產者配置類ProducerConfig

@Configuration
@EnableKafka //啓用註解kafka
public class ProducerConfig {

    /**
     * 註冊kafka模板
     *
     * @return org.springframework.kafka.core.KafkaTemplate<java.lang.String,java.lang.String>
     * @author: zhihao
     * @date: 2020/3/24
     */
    @Bean
    public KafkaTemplate<String, String> kafkaTemplate() {
        return new KafkaTemplate<>(producerFactory());
    }
    /**
     * 註冊生產者工廠,並配置生產者配置
     *
     * @return org.springframework.kafka.core.ProducerFactory<java.lang.String,java.lang.String>
     * @author: zhihao
     * @date: 2020/3/24
     */
    @Bean
    public ProducerFactory<String, String> producerFactory() {
        HashMap<String, Object> configs = new HashMap<>();
        //bootstrapServers爲Kafka生產者的地址
        configs.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG,"localhost:9092");
        //確認配置
        configs.put(ProducerConfig.ACKS_CONFIG, "all");
        //重試次數
        configs.put(ProducerConfig.RETRIES_CONFIG, 1);
        //批處理數量,每當將多個記錄發送到同一分區時,生產者將嘗試將記錄一起批處理成更少的請求。這有助於提高客戶端和服務器的性能
        configs.put(ProducerConfig.BATCH_SIZE_CONFIG, 16384);
        //批處理延遲時間上限:即10ms過後,不管是否達到批處理數,都直接發送一次請求
        configs.put(ProducerConfig.LINGER_MS_CONFIG, 10);
        //緩衝區內存配置 32MB
        configs.put(ProducerConfig.BUFFER_MEMORY_CONFIG, 33554432);
        //key與value序列化方式
        configs.put(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, StringSerializer.class);
        configs.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, StringSerializer.class);
        DefaultKafkaProducerFactory<String,String> kvDefaultKafkaProducerFactory = new DefaultKafkaProducerFactory<>(configs);
        return kvDefaultKafkaProducerFactory;
    }
    
    /** 
     * 創建kafka主題 
     *
     * @param  
     * @return org.apache.kafka.clients.admin.NewTopic 
     * @author: zhihao
     * @date: 2020/3/24 
     */
    /*@Bean
    public NewTopic foo() {
        //第一個是參數是topic名字,第二個參數是分區個數,第三個是topic的複製因子個數
        //當broker個數爲1個時會創建topic失敗,
        //提示:replication factor: 2 larger than available brokers: 1
        //只有在集羣中才能使用kafka的備份功能
        return new NewTopic("mykafkaDemo", 1, (short) 1);
    }*/
}

2.3 編寫消費者配置ConsumerConfig

@Configuration
@EnableKafka //啓用註解kafka
public class ConsumerConfig {

    /** 
     * 默認的卡夫卡消費工廠,並配置消費者配置
     *
     * @return org.springframework.kafka.core.DefaultKafkaConsumerFactory<java.lang.String,java.lang.String> 
     * @author: zhihao
     * @date: 2020/3/24 
     */
    @Bean
    public DefaultKafkaConsumerFactory<String, String> defaultKafkaConsumerFactory() {
        Map<String,Object> properties =  new HashMap<>();
        properties.put(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG,"localhost:9092");
        //費者羣組ID,發佈-訂閱模式,即如果一個生產者,多個消費者都要消費,那麼需要定義自己的羣組,同一羣組內的消費者只有一個能消費到消息
        properties.put(ConsumerConfig.GROUP_ID_CONFIG,"Mykafka");
        //自動提交
        properties.put(ConsumerConfig.ENABLE_AUTO_COMMIT_CONFIG,"false");
        //提交間隔
        properties.put(ConsumerConfig.AUTO_COMMIT_INTERVAL_MS_CONFIG, "1000");
        //會話超時MS配置
        properties.put(ConsumerConfig.SESSION_TIMEOUT_MS_CONFIG, "15000");
        //自動偏移重設
        //earliest:當各分區下有已提交的offset時,從提交的offset開始消費;無提交的offset時,從頭開始消費
        //latest:當各分區下有已提交的offset時,從提交的offset開始消費;無提交的offset時,消費新產生的該分區下的數據
        //none:topic各分區都存在已提交的offset時,從offset後開始消費;只要有一個分區不存在已提交的offset,則拋出異常
        //exception:直接拋出異常
        properties.put(ConsumerConfig.AUTO_OFFSET_RESET_CONFIG, "latest");
        //key與value序列化方式
        properties.put(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG,StringDeserializer.class);
        properties.put(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG,StringDeserializer.class);
        //設置批量參數,一次調用返回的最大記錄數
        properties.put(ConsumerConfig.MAX_POLL_RECORDS_CONFIG, 1000);
        DefaultKafkaConsumerFactory<String, String> DefaultKafkaConsumerFactory = new DefaultKafkaConsumerFactory<>(properties);
        return DefaultKafkaConsumerFactory;
    }

    /**
     * 併發Kafka偵聽器容器工廠
     *
     * @return org.springframework.kafka.config.ConcurrentKafkaListenerContainerFactory<java.lang.String,java.lang.String>
     * @author: zhihao
     * @date: 2020/3/24
     */
    @Bean("kafkaListenerContainerFactory")
    public ConcurrentKafkaListenerContainerFactory<String, String> kafkaListenerContainerFactory() {
        ConcurrentKafkaListenerContainerFactory<String, String> factory = new ConcurrentKafkaListenerContainerFactory<>();
        factory.setConsumerFactory(defaultKafkaConsumerFactory());
        factory.setConcurrency(3);
        //批處理偵聽器
        factory.setBatchListener(true);
        //設置輪詢超時
        factory.getContainerProperties().setPollTimeout(3000);
        //設置回覆模板
        factory.setReplyTemplate(this.kafkaTemplate());
        //手動提交確認模式
        factory.getContainerProperties().setAckMode(ContainerProperties.AckMode.MANUAL_IMMEDIATE);
        return factory;
    }
    
	/** 
     * 註冊監聽類到容器,可以使用註解方式註冊(這裏是的demo沒配置包掃描) 
     *
     * @return com.zhihao.AnnotationMessage 
     * @author: zhihao
     * @date: 2020/3/24 
     */
    @Bean
    public AnnotationListenerMessage annotationListenerMessage(){
        return new AnnotationListenerMessage();
    }
    
    @Bean
    public ResultListenerMessage resultListenerMessage(){
        return new ResultListenerMessage();
    }
}

配置類上需要@EnableKafka註釋才能在Spring託管Bean上檢測@KafkaListener註解

2.4 編寫消費監AnnotationListenerMessage聽類進行消費

public class AnnotationListenerMessage {

    private Logger logger = LoggerFactory.getLogger(this.getClass());

    /**
     *  消費消息
     *  <p>
     *      消費者分組的組名爲Mykafka
     *      監聽的主題是mykafkaDemo
     *     @SendTo(value = "result")可選, 進行監聽消費成功後的轉發,參數是另一個監聽類的主題
     *  </p>
     *
     * @param message
     * @param acknowledgment
     * @author: zhihao
     * @date: 2020/3/24
     */
    @KafkaListener(groupId = "Mykafka",topics = "mykafkaDemo")
    @SendTo(value = "result") //可選
    public void myAnnotationMessage(String message,Acknowledgment acknowledgment){
        logger.info("接收消息: {}", message);
        //最終提交確認接收到消息  手動提交 offset
        acknowledgment.acknowledge();
    }
}

2.5 編寫成功消費監聽類ResultListenerMessage

可選操作!

public class ResultListenerMessage {

    private Logger logger = LoggerFactory.getLogger(this.getClass());

    /** 
     * 監聽result主題 
     *
     * @param message
     * @param acknowledgment 
     * @author: zhihao
     * @date: 2020/3/24 
     */
    @KafkaListener(topics = "result")
    public void myAnnotationMessage(String message, Acknowledgment acknowledgment){
        logger.info("成功消費消息: {}", message);
        //最終提交確認接收到消息  手動提交 offset
        acknowledgment.acknowledge();
    }
}

2.6 發送複雜的消息 (另一篇文章)

目前只發送了簡單的字符串類型的消息,我們可以自定義消息轉換器來發送複雜的消息。

1.定義一個entity對象(省略)

  1. 修改生產者工廠序列化方式
  2. 修改模板發送泛型
 	@Bean
    public ProducerFactory<String, Message> producerFactory() {
   		...............
        //value使用kafka提供的JsonSerializer
        configs.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, JsonSerializer.class);
        //修改爲Object
        DefaultKafkaProducerFactory<String,Message> kvDefaultKafkaProducerFactory = new DefaultKafkaProducerFactory<>(configs);
        return kvDefaultKafkaProducerFactory;
    }
//kafka模板類型也修改爲Message
	@Bean
    public KafkaTemplate<String, Message> kafkaTemplate() {
        return new KafkaTemplate<>(producerFactory());
    }

發送測試類修改爲:

	@Autowired
    private KafkaTemplate<String,Message> kafkaTemplate;

    @Test
    public void sendMessage() throws InterruptedException {
        ListenableFuture<SendResult<String, Message>> mykafkaDemo = null;
        //int i = 1;
        for (int i = 0; i < 10; i++) {
            mykafkaDemo = kafkaTemplate.send("mykafkaDemo", "key" + i, new Message("love", String.valueOf(i)));
           final int j = i;
            //添加回調......
            Thread.sleep(1000);
        }
    }

2.7 接收復雜消息

1.修改消費者工廠序列化方式

2.修改偵聽器容器工廠泛型

 	@Bean
    public DefaultKafkaConsumerFactory<String, Message> defaultKafkaConsumerFactory() {
     	//..............
        //Map容器序列化方式註釋,使用構造方法的
        DefaultKafkaConsumerFactory<String, Message> DefaultKafkaConsumerFactory
                = new DefaultKafkaConsumerFactory<>(properties,new StringDeserializer(),new JsonDeserializer<>(Message.class));
        return DefaultKafkaConsumerFactory;
    }
//---------------------------------------------------------

	@Bean("kafkaListenerContainerFactory")
    public ConcurrentKafkaListenerContainerFactory<String, Message> kafkaListenerContainerFactory() {
        ConcurrentKafkaListenerContainerFactory<String, Message> factory = new ConcurrentKafkaListenerContainerFactory<>();
        //.........
        return factory;
    }

接收監聽類修改爲:

	@KafkaListener(groupId = "Mykafka",topics = "mykafkaDemo")
    public String myAnnotationMessage(Message message,
                                      @Header(KafkaHeaders.RECEIVED_MESSAGE_KEY) String key,
                                      Acknowledgment acknowledgment){
        logger.info("接收消息message: {}", message.toString());
        logger.info("接收消息key: {}", key);
        //最終提交確認接收到消息  手動提交 offset
        acknowledgment.acknowledge();
        //返回成功消費信息
        return message.getMessage();
    }

注意事項:

構造消費者工廠使用集合指定序列化properties.put(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG, JsonDeserializer.class); 會序列化失敗。

發送的對象沒有無參構造方法時候,會序列化失敗!

3. @KafkaListener詳解

3.1 還可以同時監聽來自多個Topic的消息:

@KafkaListener(topics = "mykafkaDemo1, mykafkaDemo2")

3.2 還可以通過@KafkaListener來指定只接收來自特定分區的消息:

@KafkaListener(groupId = "Mykafka",
        topicPartitions = @TopicPartition(topic = "mykafkaDemo",
                partitionOffsets = {
                        @PartitionOffset(partition = "1", initialOffset = "0")
            }))
public void listen(String message,
                   @Header(KafkaHeaders.RECEIVED_PARTITION_ID) int partition) {
    logger.info("接收消息: {},partition:{}", message, partition);
}

如果不需要指定initialOffset,上面代碼可以簡化爲:

@KafkaListener(groupId = "Mykafka", topicPartitions = @TopicPartition(topic = "mykafkaDemo", partitions = { "0", "1" }))

您可以在partitionspartitionOffsets屬性中指定每個分區,但不能兩個都指定。

3.3containerFactory屬性指定使用其他容器工廠(例如創建多個自動提交的容器工廠)

3.4 通過@Header註解獲取其他信息

@KafkaListener(id = "qux", topicPattern = "myTopic1")
public void listen(@Payload String foo,
        @Header(KafkaHeaders.RECEIVED_MESSAGE_KEY) Integer key, //收到的消息key
        @Header(KafkaHeaders.RECEIVED_PARTITION_ID) int partition,//收到的分區ID
        @Header(KafkaHeaders.RECEIVED_TOPIC) String topic, //收到的主題
        @Header(KafkaHeaders.RECEIVED_TIMESTAMP) long ts //收到的時間戳
        ) {

以上例子都是發送非阻塞(異步),**如果需要阻塞(同步)**調用send().get()

4.消息過濾器

我們可以爲消息監聽添加過濾器來過濾一些特定的信息。我們在消費者配置類KafkaConsumerConfigkafkaListenerContainerFactory方法裏配置過濾規則:

/**
     * 併發Kafka偵聽器容器工廠
     *
     * @return org.springframework.kafka.config.ConcurrentKafkaListenerContainerFactory<java.lang.String,java.lang.String>
     * @author: zhihao
     * @date: 2020/3/24
     */
    @Bean("kafkaListenerContainerFactory")
    public ConcurrentKafkaListenerContainerFactory<String, String> kafkaListenerContainerFactory() {
		.......
        //設置過濾信息
        factory.setRecordFilterStrategy(new RecordFilterStrategy<String, String>() {
            @Override
            public boolean filter(ConsumerRecord<String, String> consumerRecord) {
                //信息中value包含love669就返回true過濾不進行消費
                return consumerRecord.value().contains("love669");
            }
        });
        return factory;
    }

擴展資料:

XML方式項目代碼

註解方式項目代碼

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章