Author:赵志乾
Date:2018-10-21
Declaration:All Right Reserved!!!
ProducerRecord.java
该类的实例用于存放生产者向kafka集群发送的单条消息记录。其内容如下,共包含6个属性字段。其中的topic字段用于指定该消息记录的一级分属,partition字段和key字段用于指定该消息记录的二级分属,value字段用于存放该消息记录的有效载荷,timestamp字段用于指定时间戳,headers字段用于指定.......。
topic字段指定消息记录的一级分属:kafka集群可以作为消息总线来使用,此时集群可以接收位于不同系统中的生产者发送来的不同类别的消息,而topic字段便可认为是逻辑层面的一种划分。
partition字段和key字段指定消息记录的二级分属:kafka集群为了提高消息投递和消费的并发度,引入了分区概念,对消息记录进行二级分属指定。这两个字段属于可选字段,不同的组合方式对应不同的划分策略。
partition和key字段决定的划分策略:
1、如果partiton字段不空,则直接由该字段指定具体分区,实现分区的定投;
2、如果partition字段为空,且key字段不为空,则通过对key值进行hash,来确定消息记录应归属的二级归属;
3、如果partition和key字段均为空,则对分区进行轮询投递,实现负载均衡;
value字段存放消息记录有效载荷:生产者真正要发布的消息内容会存放于value字段;
timestamp字段指定时间戳:如果用户没有指定该字段,则其会有生产者自动填充。而其最终的值是由topic中指定的时间戳类型来决定的,如果指定为创建时间,则该值由生产者客户端填写;如果指定为日志追加时间,则该值会由broker在将消息记录持久化后用当前时间进行覆盖。
注:在构造该类的实例时,要保证主题不能为空,分区号如果设置的话,要保证其值不小于0的整数,而时间戳如果设置的话,也要保证其值为不小于0的整数。
package org.apache.kafka.clients.producer;
import org.apache.kafka.common.header.Header;
import org.apache.kafka.common.header.Headers;
import org.apache.kafka.common.header.internals.RecordHeaders;
/*该类的实例用于存放生产者要向kafka集群发布的消息记录,其包括一个topic名称,用来给消息记录做逻辑层面的一级划分,即该消息记录应该被发布到kafka集群的哪个类别(主题)下;一个可选的分区号,用来给消息记录做逻辑上二级划分,即该消息记录应该被发布到kafka集群指定类别下的哪个队列(分区)中;*/
public class ProducerRecord<K, V> {
//消息主题
private final String topic;
//分区号:可选
private final Integer partition;
private final Headers headers;
//key值:可选
private final K key;
//value值:生产者要发送的有效消息载荷
private final V value;
//时间戳
private final Long timestamp;
//创建一个消息记录实例,所需指定的参数包括:主题、分区号、时间戳、key、value和headers
public ProducerRecord(String topic, Integer partition, Long timestamp, K key, V value, Iterable<Header> headers) {
if (topic == null)
throw new IllegalArgumentException("Topic cannot be null.");
if (timestamp != null && timestamp < 0)
throw new IllegalArgumentException(
String.format("Invalid timestamp: %d. Timestamp should always be non-negative or null.", timestamp));
if (partition != null && partition < 0)
throw new IllegalArgumentException(
String.format("Invalid partition: %d. Partition number should always be non-negative or null.", partition));
this.topic = topic;
this.partition = partition;
this.key = key;
this.value = value;
this.timestamp = timestamp;
this.headers = new RecordHeaders(headers);
}
//创建一个消息记录实例,所需指定的参数包括:主题、分区号、时间戳、key、value
public ProducerRecord(String topic, Integer partition, Long timestamp, K key, V value) {
this(topic, partition, timestamp, key, value, null);
}
//创建一个消息记录实例,所需指定的参数包括:主题、分区号、key、value、headers
public ProducerRecord(String topic, Integer partition, K key, V value, Iterable<Header> headers) {
this(topic, partition, null, key, value, headers);
}
//创建一个消息记录实例,所需指定的参数包括:主题、分区号、key值和消息有效载荷value值
public ProducerRecord(String topic, Integer partition, K key, V value) {
this(topic, partition, null, key, value, null);
}
//创建一个消息记录实例,所需指定的参数包括主题、key值和消息有效载荷value值
public ProducerRecord(String topic, K key, V value) {
this(topic, null, null, key, value, null);
}
//创建一个消息记录实例,所需指定的参数包括:主题和消息有效载荷value值
public ProducerRecord(String topic, V value) {
this(topic, null, null, null, value, null);
}
//返回记录的主题名称
public String topic() {
return topic;
}
public Headers headers() {
return headers;
}
//返回消息记录的key值
public K key() {
return key;
}
//返回消息记录的value值
public V value() {
return value;
}
//返回消息记录的时间戳:单位毫秒
public Long timestamp() {
return timestamp;
}
//返回消息记录要被投递到的分区号
public Integer partition() {
return partition;
}
@Override
public String toString() {
String headers = this.headers == null ? "null" : this.headers.toString();
String key = this.key == null ? "null" : this.key.toString();
String value = this.value == null ? "null" : this.value.toString();
String timestamp = this.timestamp == null ? "null" : this.timestamp.toString();
return "ProducerRecord(topic=" + topic + ", partition=" + partition + ", headers=" + headers + ", key=" + key + ", value=" + value +
", timestamp=" + timestamp + ")";
}
@Override
public boolean equals(Object o) {
if (this == o)
return true;
else if (!(o instanceof ProducerRecord))
return false;
ProducerRecord<?, ?> that = (ProducerRecord<?, ?>) o;
if (key != null ? !key.equals(that.key) : that.key != null)
return false;
else if (partition != null ? !partition.equals(that.partition) : that.partition != null)
return false;
else if (topic != null ? !topic.equals(that.topic) : that.topic != null)
return false;
else if (headers != null ? !headers.equals(that.headers) : that.headers != null)
return false;
else if (value != null ? !value.equals(that.value) : that.value != null)
return false;
else if (timestamp != null ? !timestamp.equals(that.timestamp) : that.timestamp != null)
return false;
return true;
}
@Override
public int hashCode() {
int result = topic != null ? topic.hashCode() : 0;
result = 31 * result + (partition != null ? partition.hashCode() : 0);
result = 31 * result + (headers != null ? headers.hashCode() : 0);
result = 31 * result + (key != null ? key.hashCode() : 0);
result = 31 * result + (value != null ? value.hashCode() : 0);
result = 31 * result + (timestamp != null ? timestamp.hashCode() : 0);
return result;
}
}