从春季启动应用程序调用ConsumConsumerSeekCallback寻求

时间:2018-12-03 22:04:45

标签: spring-kafka

这是我的设置:

ConsumerSeekAware实现:

public class ReplayJobKafkaConsumer implements ConsumerSeekAware, AcknowledgingMessageListener<String, String> {

    @Override
    public void onPartitionsAssigned(Map<TopicPartition, Long> map, ConsumerSeekCallback consumerSeekCallback) {

    }

    @Override
    public void onIdleContainer(Map<TopicPartition, Long> map, ConsumerSeekCallback consumerSeekCallback) {

    }

    private static final ThreadLocal<ConsumerSeekCallback> seekCallBack = new ThreadLocal<>();

    private static ConsumerSeekCallback consumerSeekCallback;;

    @Override
    public void registerSeekCallback(ConsumerSeekCallback callback) {
        this.seekCallBack.set(callback);
        consumerSeekCallback = callback;
    }

    public void onMessage(final ConsumerRecord<String, String> data, final Acknowledgment acknowledgment) {
    }

    public static ThreadLocal<ConsumerSeekCallback> getSeekCallback(){
        return seekCallBack;
    }

    public static ConsumerSeekCallback getAnotherSeekCallback(){
        return consumerSeekCallback;
    }
}

我的SpringBoot应用程序近似为:

@SpringBootApplication
public class ReplayJobApplication{
...
public void run(final String... args){
        context = SpringApplication.run(ReplayJobApplication.class, args);
        ReplayJobKafkaConsumer.getAnotherSeekCallback().seek("top", 0, 23);
    }
...}

以上设置有效。现在,我可以使用 java -jar -Dstart.offset=0....

但是仅当seekcallback变量不是ThreadLocal时才有效。我需要可以在Spring Boot应用程序上访问它,因为这就是我打算运行此使用者的方式。 TEMP-TOPIC的其他使用者仍然可以处理,但我打算根据需要在开始和结束偏移量的基础上运行该使用者。虽然可以在使用者中读取命令行参数,但我所担心的是

  1. 回调变量是静态的(我可能无法创建ReplayJobKafkaConsumer的实例

  2. 它是一个普通变量,而不是ThreadLocal

尽管此容器的使用寿命只会从头到尾,但我不知道此设置是否有缺陷,需要确认此实现是否可行。

希望我已经提供了所有必要的信息

金枪鱼

1 个答案:

答案 0 :(得分:0)

您似乎对正在发生的事情有一些根本的误解。

  1. ThreadLocal是必需的,因为Kafka使用者对象不是线程安全的。如果将回调存储在TL中,则可以在运行时执行任意查找操作-从onMessage方法开始,或者在没有消息时通过侦听ListenerContainerIdleEvent

  2. 您无法从另一个线程执行任意搜索ReplayJobKafkaConsumer.getAnotherSeekCallback().seek("top", 0, 23);

  3. 在分配分区之前,您不能执行任意查找。

因此,正如我在其他答案/评论中告诉您的那样,分配分区时必须进行查找。

@Override
public void onPartitionsAssigned(Map<TopicPartition, Long> map, ConsumerSeekCallback consumerSeekCallback) {
    // Do the seeks here using the `consumerSeekCallback` parameter.
}

在现代版本的spring-kafka中,除非您想在运行时执行任意查找(在初始查找之后),否则不需要使用ConsumerSeekAware。您可以改用ConsumerAwareRebalanceListener

相关问题