前言
对于Java web服务通常都会使用spring-boot作为web基础框架,今天就从spring的角度分析一下kafka是如何注入到spring容器中并且如何使用的。本文主要针对spring-kafka.2.5.5.RELEASE版本进行分析,不涉及kafka-clients原理讲解。
了解Springframework
Bean的生命周期:
spring容器从全局的角度来看就是管理web系统运行过程中所需要的对象,其中bean的生命周期就是系统运行所依赖对象的 创建过程->初始化过程->对象的销毁过程。
import注解和ImportBeanDefinitionRegistrar使用:
-
ImportBeanDefinitionRegistrar类只能通过其他类@Import的方式来加载,通常是启动类或配置类。
-
使用@Import,如果括号中的类是ImportBeanDefinitionRegistrar的实现类,则会调用接口方法,将其中要注册的类注册成bean
-
实现该接口的类拥有注册bean的能力。
BeanPostProcess作用:
利用模板的特性,spring容器在bean做初始化的前后都会调用到BeanPostProcess接口内部的方法,用于做一些特殊处理。
自己实现一个扩展该如何实现
根据bean的生命周期,和kafka生产消费的特性,如果我们自己要实现一个spring-kafka的话需要实现以下几个功能。
- 需要通过import注解或者ImportBeanDefinitionRegistrar的方式将kafka-client的客户端注入到spring容器中。
- bean初始化的过程中需要将消费者部分的代码启动,用来接收消息
- 在程序运行过程中需要使用生产者发送消息,内部需要使用kafka-client的实例
- 需要识别一些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内部发送消息的核心代码,其内部做了三件事情。
-
从kafka客户端中获取一个Producer用来发送消息
-
对发送的消息进行封装,满足kafka客户端发送消息的数据标准
-
调用send进行发送消息
-
对于返回结果做异步通知
-
对于异常情况进行处理
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