Kafka0.9版本以后关于producer和consumer的实现跟0.8版本相比有了很大的不同,目前网上关于新版的生产者和消费者的示例代码很少,因此想要实现在生产中可以使用的producer和consumer代码。本文会主要实现producer相关的代码,下一篇文章会实现多线程的consumer代码
在阅读本文之前,强烈建议先阅读以下一篇博文,将新版kafka producer的原理讲解的很透彻:Kafka producer介绍
大家在了解了producer的基本原理之后,我们来看下代码的具体实现:源代码地址
<dependency>
<groupId>org.apache.kafkagroupId>
<artifactId>kafka_2.12artifactId>
<version>1.0.0version>
<exclusions>
<exclusion>
<groupId>org.apache.zookeepergroupId>
<artifactId>zookeeperartifactId>
exclusion>
<exclusion>
<groupId>org.slf4jgroupId>
<artifactId>slf4j-log4j12artifactId>
exclusion>
<exclusion>
<groupId>junitgroupId>
<artifactId>junitartifactId>
exclusion>
exclusions>
dependency>
这个pom会在你的项目工程中引入两个jar包:
org.apache.kafka:kafka-clients:1.0.0
org.apache.kafka:kafka_2.12:1.0.0
由于在我的项目中有单独的zk和日志jar包,所以在引入kafka的时候需要将相关的包排除掉
代码如下
package com.russell.bigdata.kafka.handler;
import org.apache.kafka.clients.producer.Callback;
import org.apache.kafka.clients.producer.KafkaProducer;
import org.apache.kafka.clients.producer.ProducerRecord;
import org.apache.kafka.common.serialization.StringSerializer;
import java.util.Properties;
/**
* kafka 1.0版本的生产者 handler
*
* @author liumenghao
* @Date 2019/1/13
*/
public class ProducerHandler10 {
/**
* 序列化方法
*/
private static final String DEFAULT_SERIALIZER_CLASS = StringSerializer.class.getName();
/**
* kafka api中的生产者
*/
private KafkaProducer kafkaProducer;
/**
* kafka生产者构造方法
*
* @param brokerList kafka节点信息
*/
public ProducerHandler10(String brokerList) {
Properties producerConfig = createProducerConfig(brokerList, DEFAULT_SERIALIZER_CLASS);
kafkaProducer = new KafkaProducer(producerConfig);
}
/**
* 发送消息到kafka
*
* @param topic 消息被发送到的topic
* @param value 发送的消息的内容
*/
public void sendMessage(String topic, String value) {
ProducerRecord data = new ProducerRecord(topic, value);
kafkaProducer.send(data);
}
/**
* 发送消息到kafka,可以使用回调函数对发送结果进行处理
*
* @param topic
* @param value
* @param callback
*/
public void sendMessage(String topic, String value, Callback callback) {
ProducerRecord data = new ProducerRecord(topic, value);
kafkaProducer.send(data, callback);
}
/**
* 关闭kafka,释放资源
*/
public void close() {
kafkaProducer.close();
}
/**
* 创建kafka配置类
*
* @param brokerList
* @param serializerClass
* @return
*/
private Properties createProducerConfig(String brokerList, String serializerClass) {
Properties props = new Properties();
// broker 列表
props.put("bootstrap.servers", brokerList);
// 设置对key序列化的类
props.put("key.serializer", serializerClass);
// 设置对value序列化的类
props.put("value.serializer", serializerClass);
/**
* 0 不等待结果返回
* 1 等待至少有一个服务器返回数据接收标识
* -1或all 表示必须接受到所有的服务器返回标识,及同步写入
*/
props.put("request.required.acks", "1");
/**
* 内部发送数据是异步还是同步
* sync 同步,默认
* async异步
*/
props.put("producer.type", "async");
return props;
}
}
这个类就是在Kafka Api中的KafkaProducer类上封装了一层
关键的几个类
1、org.apache.kafka.clients.producer.KafkaProducer
生产者的构造方法类,用来进行消息的发送操作
2、org.apache.kafka.clients.producer.ProducerRecord
发送到kafka的数据的模型抽象
其中sendMessage,有两个方法。其中一个添加了回调函数Callback,可以对服务端接收到消息后返回的信息RecordMetadata进行业务相关的处理。下面我们通过测试方法来看Producer Handler的使用
package com.russell.bigdata.kafka.example;
import com.russell.bigdata.kafka.common.KafkaTopicType;
import com.russell.bigdata.kafka.handler.ProducerHandler10;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.apache.kafka.clients.producer.RecordMetadata;
import static com.russell.bigdata.kafka.common.Constants.KAFKA_BROKER;
/**
* 测试使用,感受kafka java producer api的使用方式
*
* @author liumenghao
* @Date 2019/2/22
*/
@Slf4j
@Data
public class ProducerTest {
private static int count;
public static void main(String[] args) throws Exception {
ProducerHandler10 producer = new ProducerHandler10(KAFKA_BROKER);
while (true) {
Thread.sleep(1000);
String topic = KafkaTopicType.THREE_PARTITION_TOPIC.getName();
String message = "测试生产数据 " + count;
producer.sendMessage(topic, message,
(metadata, exception) -> callback(metadata, exception));
log.info("测试生产数据" + " " + count);
count++;
}
}
/**
* 回调函数,当kafka发送数据完成后,会从服务端返回一个RecordMetadata
*
* @param metadata
* @param exception
*/
private static void callback(RecordMetadata metadata, Exception exception) {
String topic = metadata.topic();
Integer partition = metadata.partition();
Long offset = metadata.offset();
log.info("topic={}, partition={}, offset={}", topic, partition, offset);
}
}
直接使用带有KafkaCallback参数的sendMessage重载方法进行测试,当数据发到到服务端成功后,将数据写入的topic,partition以及offset的信息打印出来。最终的测试结果如下:
测试生产数据 0
topic=kafka_partitions_topic, partition=2, offset=382
测试生产数据 1
topic=kafka_partitions_topic, partition=1, offset=383
测试生产数据 2
topic=kafka_partitions_topic, partition=0, offset=382
测试生产数据 3
topic=kafka_partitions_topic, partition=2, offset=383
本文只是从代码层面讲解了1.0.0版本的Kafka Producer的实现,对其中的一些具体的类,例如KafkaProducer、ProducerRecord等没有深入讲解,因为我个人一直秉持的一个理念是,最好的学习方式就是直接读源码。示例代码相当于是给了你一个入门的概念,然后顺着这个demo去深入。