2

我正在将一个简单的 Kafka 消费者应用程序从现有框架中移出,并且觉得 spring-cloud-stream 是一种简单的方法。我使用 Initializr 来引导应用程序,该应用程序现在使用 Spring-Boot v1.3.3 和 Spring-Cloud-Stream v1.0.0-RC1。该应用程序非常简单,它所要做的就是从 Kafka 中挑选一条消息,反序列化 JSON 编码对象并将其传递给我们现有的库。开始时我只使用了 LogSink 示例,因为最终我不会做太多其他事情(只是反序列化并将对象传递给不同的方法)。

这一切都很好:它连接到 Kafka,接收消息并将它(作为字节 [])传递到我的接收器。但是,EmbeddedHeadersMessageConverter 记录了 StringIndexOutOfBoundsException:

2016-04-11 10:06:50.287 ERROR 11464 --- [pool-1-thread-1] fkaMessageChannelBinder$ReceivingHandler : Could not convert message: 7B2267656E65726174696F6E223A3 [...]
java.lang.StringIndexOutOfBoundsException: String index out of range: 2009
    at java.lang.String.checkBounds(String.java:373) ~[na:1.8.0_25]
    at java.lang.String.<init>(String.java:413) ~[na:1.8.0_25]
    at org.springframework.cloud.stream.binder.EmbeddedHeadersMessageConverter.oldExtractHeaders(EmbeddedHeadersMessageConverter.java:131) ~[spring-cloud-stream-1.0.0.RC1.jar:1.0.0.RC1]
    at org.springframework.cloud.stream.binder.EmbeddedHeadersMessageConverter.extractHeaders(EmbeddedHeadersMessageConverter.java:104) ~[spring-cloud-stream-1.0.0.RC1.jar:1.0.0.RC1]
    at org.springframework.cloud.stream.binder.kafka.KafkaMessageChannelBinder$ReceivingHandler.handleRequestMessage(KafkaMessageChannelBinder.java:583) ~[spring-cloud-stream-binder-kafka-1.0.0.RC1.jar:1.0.0.RC1]
    at org.springframework.integration.handler.AbstractReplyProducingMessageHandler.handleMessageInternal(AbstractReplyProducingMessageHandler.java:99) [spring-integration-core-4.2.5.RELEASE.jar:na]
    at org.springframework.integration.handler.AbstractMessageHandler.handleMessage(AbstractMessageHandler.java:127) [spring-integration-core-4.2.5.RELEASE.jar:na]
    at org.springframework.integration.channel.FixedSubscriberChannel.send(FixedSubscriberChannel.java:69) [spring-integration-core-4.2.5.RELEASE.jar:na]
    at org.springframework.integration.channel.FixedSubscriberChannel.send(FixedSubscriberChannel.java:63) [spring-integration-core-4.2.5.RELEASE.jar:na]
    at org.springframework.messaging.core.GenericMessagingTemplate.doSend(GenericMessagingTemplate.java:115) [spring-messaging-4.2.5.RELEASE.jar:4.2.5.RELEASE]
    at org.springframework.messaging.core.GenericMessagingTemplate.doSend(GenericMessagingTemplate.java:45) [spring-messaging-4.2.5.RELEASE.jar:4.2.5.RELEASE]
    at org.springframework.messaging.core.AbstractMessageSendingTemplate.send(AbstractMessageSendingTemplate.java:105) [spring-messaging-4.2.5.RELEASE.jar:4.2.5.RELEASE]
    at org.springframework.integration.endpoint.MessageProducerSupport.sendMessage(MessageProducerSupport.java:105) [spring-integration-core-4.2.5.RELEASE.jar:na]
    at org.springframework.integration.kafka.inbound.KafkaMessageDrivenChannelAdapter.access$300(KafkaMessageDrivenChannelAdapter.java:43) [spring-integration-kafka-1.3.0.RELEASE.jar:na]
    at org.springframework.integration.kafka.inbound.KafkaMessageDrivenChannelAdapter$AutoAcknowledgingChannelForwardingMessageListener.doOnMessage(KafkaMessageDrivenChannelAdapter.java:171) [spring-integration-kafka-1.3.0.RELEASE.jar:na]
    at org.springframework.integration.kafka.listener.AbstractDecodingMessageListener.onMessage(AbstractDecodingMessageListener.java:50) [spring-integration-kafka-1.3.0.RELEASE.jar:na]
    at org.springframework.integration.kafka.listener.QueueingMessageListenerInvoker$KafkaMessageDispatchingSubscriber.onNext(QueueingMessageListenerInvoker.java:221) [spring-integration-kafka-1.3.0.RELEASE.jar:na]
    at org.springframework.integration.kafka.listener.QueueingMessageListenerInvoker$KafkaMessageDispatchingSubscriber.onNext(QueueingMessageListenerInvoker.java:209) [spring-integration-kafka-1.3.0.RELEASE.jar:na]
    at reactor.core.processor.util.RingBufferSubscriberUtils.route(RingBufferSubscriberUtils.java:67) [reactor-core-2.0.7.RELEASE.jar:na]
    at reactor.core.processor.RingBufferProcessor$BatchSignalProcessor.run(RingBufferProcessor.java:789) [reactor-core-2.0.7.RELEASE.jar:na]
    at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511) [na:1.8.0_25]
    at java.util.concurrent.FutureTask.run(FutureTask.java:266) [na:1.8.0_25]
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) [na:1.8.0_25]
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) [na:1.8.0_25]
    at java.lang.Thread.run(Thread.java:745) [na:1.8.0_25]

https://github.com/spring-cloud/spring-cloud-stream/issues/209似乎表明问题是缺少 Kafka 标头,这是真的,没有。但是那里提到的解决方案是添加

spring.cloud.stream.binder.kafka.mode=raw

到我的应用程序配置。不幸的是,这对我不起作用。此外,STS 实际上对各个属性都有自动完成功能,它建议

spring.cloud.stream.kafka.binder.mode=raw

两个(单独或组合)都没有任何区别,仍在记录异常。

我已经使用 Spring 多年了,但这将是我的第一个 Spring-Boot/Spring-Cloud 应用程序。

这是应用程序代码:

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.stream.annotation.EnableBinding;
import org.springframework.cloud.stream.annotation.StreamListener;
import org.springframework.cloud.stream.messaging.Sink;
import org.springframework.integration.annotation.ServiceActivator;

@SpringBootApplication
public class UpdateApplication {
    private static Logger logger  = LoggerFactory.getLogger(UpdateApplication.class);

    public static void main(String[] args) {
        SpringApplication.run(UpdateApplication.class, args);
    }

    @EnableBinding(Sink.class)
    public static class UpdateHandler {

        @StreamListener(Sink.INPUT)
        //@ServiceActivator(inputChannel=Sink.INPUT)
        public void loggerSink(Object payload) {
            logger.info("Received: " + payload);
        }        
    }
}

我尝试了@ServiceActivator 和@StreamListener 注释,在这种情况下似乎没有什么不同。

我的 application.properties 看起来像这样:

spring.cloud.stream.bindings.input.binder=kafka
spring.cloud.stream.bindings.input.destination=updates
spring.cloud.stream.bindings.input.group=update-client
spring.cloud.stream.kafka.binder.brokers=brokerName
spring.cloud.stream.kafka.binder.zkNodes=zookeeperName
spring.cloud.stream.kafka.binder.mode=raw

任何帮助摆脱此错误将不胜感激。

附带说明:由于我刚开始尝试使用 spring-cloud-stream 我添加了

spring.cloud.stream.bindings.updates.consumer.resetOffsets=true
spring.cloud.stream.bindings.updates.consumer.startOffset=earlist

到配置以避免每次我重新启动时都必须发送新消息,但这不起作用。

4

2 回答 2

4

由于该RC选项已移至.consumer.配置选项。

所以,现在你必须这样做:

spring.cloud.stream.bindings.input.consumer.mode=raw

在参考手册中查看更多信息。

于 2016-04-11T19:29:53.297 回答
0

spring.cloud.stream.bindings.input.consumer.headerMode=raw

适用于 1.1.0.RELEASE 版本。

于 2017-02-07T10:00:00.797 回答