spring-kafka源码分析-01

787 阅读3分钟

前言

对于Java web服务通常都会使用spring-boot作为web基础框架,今天就从spring的角度分析一下kafka是如何注入到spring容器中并且如何使用的。本文主要针对spring-kafka.2.5.5.RELEASE版本进行分析,不涉及kafka-clients原理讲解。

了解Springframework

Bean的生命周期:

spring容器从全局的角度来看就是管理web系统运行过程中所需要的对象,其中bean的生命周期就是系统运行所依赖对象的 创建过程->初始化过程->对象的销毁过程。

import注解和ImportBeanDefinitionRegistrar使用:

  1. ImportBeanDefinitionRegistrar类只能通过其他类@Import的方式来加载,通常是启动类或配置类。

  2. 使用@Import,如果括号中的类是ImportBeanDefinitionRegistrar的实现类,则会调用接口方法,将其中要注册的类注册成bean

  3. 实现该接口的类拥有注册bean的能力。

BeanPostProcess作用:

利用模板的特性,spring容器在bean做初始化的前后都会调用到BeanPostProcess接口内部的方法,用于做一些特殊处理。

自己实现一个扩展该如何实现

根据bean的生命周期,和kafka生产消费的特性,如果我们自己要实现一个spring-kafka的话需要实现以下几个功能。

  1. 需要通过import注解或者ImportBeanDefinitionRegistrar的方式将kafka-client的客户端注入到spring容器中。
  2. bean初始化的过程中需要将消费者部分的代码启动,用来接收消息
  3. 在程序运行过程中需要使用生产者发送消息,内部需要使用kafka-client的实例
  4. 需要识别一些spring-kafka的配置文件信息,以及注解信息

测试代码

application.properties配置文件

server.port=9527
spring.kafka.consumer.group-id=test-consumer-group
spring.kafka.bootstrap-servers=ip:port

生产者 KafkaProducer

@Component
public class KafkaProducer {
    // 使用kafka客户端
    @Autowired
    private KafkaTemplate kafkaTemplate;

    public void sendMsg(String msg) {
        // 异步发送消息
        ListenableFuture<SendResult<Integer, String>> future = kafkaTemplate.send("test1",
                msg);
        // 注入回调函数
        future.addCallback(new ListenableFutureCallback<SendResult<Integer, String>>() {
                @Override
                public void onFailure(Throwable throwable) {
                    System.out.println("callback fail");
                }

                @Override
                public void onSuccess(
                    SendResult<Integer, String> integerStringSendResult) {
                    System.out.println("callback success");
                }
            });
        kafkaTemplate.flush();
    }
}

消费者 KafkaConsumer

@Component
public class KafkaConsumer {

   // 注入队列监听器
   @KafkaListener(topics = {"test1"})
   public void onMessage(ConsumerRecord<?,?> record){
     System.out.println("consumer->"+record.value());
   }
}
      

生产者源码分析

通过上面的分析可以看到,生产者主要就是KafkaTemplate.send()方法,下面我们就来分析一下这个方法。

public ListenableFuture<SendResult<K, V>> send(String topic, V data) {
    ProducerRecord<K, V> producerRecord = new ProducerRecord<>(topic, data);// 这里同原生的使用是一致的,将消费封装为ProducerRecord
    return doSend(producerRecord);// 主要在这里
}

doSend方法,是spring-kafka内部发送消息的核心代码,其内部做了三件事情。

  1. 从kafka客户端中获取一个Producer用来发送消息

  2. 对发送的消息进行封装,满足kafka客户端发送消息的数据标准

  3. 调用send进行发送消息

  4. 对于返回结果做异步通知

  5. 对于异常情况进行处理

    protected ListenableFuture<SendResult<K, V>> doSend(ProducerRecord<K, V> producerRecord) { // 获取一个Producer用来发送消息 Producer<K, V> producer = this.getTheProducer(producerRecord.topic()); ... SettableListenableFuture<SendResult<K, V>> future = new SettableListenableFuture(); ... // 使用feature构建回调 // 调用kafka客户端的producer内部的send方法进行发送数据 Future sendFuture = producer.send(producerRecord, this.buildCallback(producerRecord, producer, future, sample)); // 返回成功处理逻辑 if (sendFuture.isDone()) { try { sendFuture.get(); } catch (Exception e){ # 异常处理逻辑 } } ... return future; }

总结:发送的方法比较简单,就是简单的通过Producer.send()来发送消息,同原生的方式基本没有区别。

下一节消费者代码分析和KafkaListener注解解析

博主简介:国内最大最权威的 Kafka中文社区,共享知识,实时掌控最新行业资讯

技术交流:请联系博主微信号:didiyun0125

社区地址:z.didi.cn/5gSF9