publicclassProducerRecord<K, V>{//所属toipcprivatefinal String topic;//所属分区privatefinal Integer partition;//头部信息privatefinal Headers headers;//消息的keyprivatefinal K key;//消息内容privatefinal V value;//时间戳privatefinal Long timestamp;
publicinterfacePartitionerextendsConfigurable, Closeable {/**
* Compute the partition for the given record.
* 根据消息计算分区,返回分区号
* @param topic The topic name
* @param key The key to partition on (or null if no key)
* @param keyBytes The serialized key to partition on( or null if no key)
* @param value The value to partition on or null
* @param valueBytes The serialized value to partition on or null
* @param cluster The current cluster metadata
*/publicintpartition(String topic, Object key,byte[] keyBytes, Object value,byte[] valueBytes, Cluster cluster);/**
* 关闭分区器
* This is called when partitioner is closed.
*/publicvoidclose();}
1.5.2 DefaultPartitioner
DefaultPartitioner是Partitioner的唯一实现类。
publicclassDefaultPartitionerimplementsPartitioner{privatefinal ConcurrentMap<String, AtomicInteger> topicCounterMap =newConcurrentHashMap<>();publicvoidconfigure(Map<String,?> configs){}/**
* Compute the partition for the given record.
*
* @param topic The topic name
* @param key The key to partition on (or null if no key)
* @param keyBytes serialized key to partition on (or null if no key)
* @param value The value to partition on or null
* @param valueBytes serialized value to partition on or null
* @param cluster The current cluster metadata
*/publicintpartition(String topic, Object key,byte[] keyBytes, Object value,byte[] valueBytes, Cluster cluster){//1.获取Topic的全部分区信息
List<PartitionInfo> partitions = cluster.partitionsForTopic(topic);//2.分区数量int numPartitions = partitions.size();if(keyBytes == null){//3.如果消息没有指定了key,就会轮询发往各个可用的分区,先获取指定topic的计数器int nextValue =nextValue(topic);//4.获取全部的可用分区
List<PartitionInfo> availablePartitions = cluster.availablePartitionsForTopic(topic);if(availablePartitions.size()>0){//5.如果有可用分区,就计数器取余,获取一个可用分区int part = Utils.toPositive(nextValue)% availablePartitions.size();return availablePartitions.get(part).partition();}else{// no partitions are available, give a non-available partition//6.如果没有可用分区,返回一个不可用的分区return Utils.toPositive(nextValue)% numPartitions;}}else{//如果消息指定了key,那就通过一定的hash算法来取余计算分区,(有可能是所有分区中的任何一个)// hash the keyBytes to choose a partitionreturn Utils.toPositive(Utils.murmur2(keyBytes))% numPartitions;}}//获取topic消息的计数器,便于轮询,首次会初始化,之后便会递增privateintnextValue(String topic){
AtomicInteger counter = topicCounterMap.get(topic);if(null == counter){
counter =newAtomicInteger(ThreadLocalRandom.current().nextInt());
AtomicInteger currentCounter = topicCounterMap.putIfAbsent(topic, counter);if(currentCounter != null){
counter = currentCounter;}}return counter.getAndIncrement();}publicvoidclose(){}}
publicinterfaceProducerInterceptor<K, V>extendsConfigurable{/**
* @param record the record from client or the record returned by the previous interceptor in the chain of interceptors.
* @return producer record to send to topic/partition
*/public ProducerRecord<K, V>onSend(ProducerRecord<K, V> record);/**
*
*/publicvoidonAcknowledgement(RecordMetadata metadata, Exception exception);/**
* This is called when interceptor is closed
*/publicvoidclose();}
消息在发送之前首先会经过拦截器,下面是方法调用栈
producer.send(record);->KafkaProducer#send()->KafkaProducer#send()@Overridepublic Future<RecordMetadata>send(ProducerRecord<K, V> record, Callback callback){// intercept the record, which can be potentially modified; this method does not throw exceptions//1.如果有拦截器配置,则调用拦截器的onSend方法处理消息,并返回处理后的消息,再将其发生,//在ProducerInterceptors里面会保存全部的ProducerInterceptor拦截器实例,并一一调用
ProducerRecord<K, V> interceptedRecord =this.interceptors == null ? record :this.interceptors.onSend(record);returndoSend(interceptedRecord, callback);}privatefinal ProducerInterceptors<K, V> interceptors;