Kafka-Consumer 源码解析 -- 数据消费

Kafka-Consumer 源码解析 -- 数据消费

前言

本文主要结合源码对 kafka consumer 拉取数据的消费过程进行分析。

数据消费

数据消费的入口存在于 ListenerConsumer 类的 pollAndInvoke 方法中,由 invokeListener(records) 进行执行。
invokeListener(records)实现为:

private void invokeListener(final ConsumerRecords<K, V> records) {
   	if (this.isBatchListener) {
   	    // 批量消费
   		invokeBatchListener(records);
   	}
   	else {
   	    // 单条消费
   		invokeRecordListener(records);
   	}
}

这里分析单条数据的消费情况:

private void invokeRecordListener(final ConsumerRecords<K, V> records) {
   	if (this.transactionTemplate != null) {
   	    // 开启事务消费数据
   		invokeRecordListenerInTx(records);
   	}
   	else {
   	    // 正常的消费数据
   		doInvokeWithRecords(records);
   	}
}	
private void doInvokeWithRecords(final ConsumerRecords<K, V> records) {
   	Iterator<ConsumerRecord<K, V>> iterator = records.iterator();
   	// 遍历数据,执行消费过程
   	while (iterator.hasNext()) {
   		final ConsumerRecord<K, V> record = iterator.next();
   		this.logger.trace(() -> "Processing " + record);
   		// 执行消费
   		doInvokeRecordListener(record, null, iterator);
   		if (this.nackSleep >= 0) {
   			handleNack(records, record);
   			break;
   		}
   	}
}	
private RuntimeException doInvokeRecordListener(final ConsumerRecord<K, V> record,
   			@SuppressWarnings(RAW_TYPES) Producer producer,
   			Iterator<ConsumerRecord<K, V>> iterator) {

   	Object sample = startMicrometerSample();
   
   	try {
   	    // 数据消费
   		invokeOnMessage(record, producer);
   		successTimer(sample);
   	}
   	catch (RuntimeException e) {
   		failureTimer(sample);
   		if (this.containerProperties.isAckOnError() && !this.autoCommit && producer == null) {
   		    // 如果设置了在出现异常时的数据提交且为手动提交形式,执行offset的提交
   			ackCurrent(record);
   		}
   		if (this.errorHandler == null) {
   			throw e;
   		}
   		try {
   		    // 执行 error handler
   			invokeErrorHandler(record, producer, iterator, e);
   		}
   		catch (RuntimeException ee) {
   			this.logger.error(ee, "Error handler threw an exception");
   			return ee;
   		}
   		catch (Error er) { // NOSONAR
   			this.logger.error(er, "Error handler threw an error");
   			throw er;
   		}
   	}
   	return null;
}

在 RecordMessagingMessageListenerAdapter 类中的 onMessage 方法执行:

public void onMessage(ConsumerRecord<K, V> record, Acknowledgment acknowledgment, Consumer<?, ?> consumer) {
   	Message<?> message;
   	if (isConversionNeeded()) {
   		message = toMessagingMessage(record, acknowledgment, consumer);
   	}
   	else {
   		message = NULL_MESSAGE;
   	}
   	if (logger.isDebugEnabled()) {
   		logger.debug("Processing [" + message + "]");
   	}
   	try {
   	    // 携带参数,执行消费
   		Object result = invokeHandler(record, acknowledgment, message, consumer);
   		if (result != null) {
   			handleResult(result, record, message);
   		}
   	}
   	catch (ListenerExecutionFailedException e) { // NOSONAR ex flow control
   		if (this.errorHandler != null) {
   			try {
   				if (message.equals(NULL_MESSAGE)) {
   					message = new GenericMessage<>(record);
   				}
   				Object result = this.errorHandler.handleError(message, e, consumer);
   				if (result != null) {
   					handleResult(result, record, message);
   				}
   			}
   			catch (Exception ex) {
   				throw new ListenerExecutionFailedException(createMessagingErrorMessage(// NOSONAR stack trace loss
   						"Listener error handler threw an exception for the incoming message",
   						message.getPayload()), ex);
   			}
   		}
   		else {
   			throw e;
   		}
   	}
}

在 InvocableHandlerMethod 中 invoke 方法会匹配方法参数,将必要参数传入method并执行:

public Object invoke(Message<?> message, Object... providedArgs) throws Exception {
    // 匹配方法参数,返回需要调用方法的实际参数,如果方法参数中有 acknowledge 参数,则会校验是否为手动提交方式 
   	Object[] args = getMethodArgumentValues(message, providedArgs);
   	if (logger.isTraceEnabled()) {
   		logger.trace("Arguments: " + Arrays.toString(args));
   	}
   	// 执行消费方法,此步实际执行为手动定义的消费方法
   	return doInvoke(args);
}

总结

整个数据消费的过程相对其余数据拉取、offset提交等比较简单明了。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值