这是我的设置:
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的其他使用者仍然可以处理,但我打算根据需要在开始和结束偏移量的基础上运行该使用者。虽然可以在使用者中读取命令行参数,但我所担心的是
回调变量是静态的(我可能无法创建ReplayJobKafkaConsumer的实例
它是一个普通变量,而不是ThreadLocal
尽管此容器的使用寿命只会从头到尾,但我不知道此设置是否有缺陷,需要确认此实现是否可行。
希望我已经提供了所有必要的信息
金枪鱼
答案 0 :(得分:0)
您似乎对正在发生的事情有一些根本的误解。
ThreadLocal
是必需的,因为Kafka使用者对象不是线程安全的。如果将回调存储在TL中,则可以在运行时执行任意查找操作-从onMessage
方法开始,或者在没有消息时通过侦听ListenerContainerIdleEvent
。
您无法从另一个线程执行任意搜索ReplayJobKafkaConsumer.getAnotherSeekCallback().seek("top", 0, 23);
。
在分配分区之前,您不能执行任意查找。
因此,正如我在其他答案/评论中告诉您的那样,分配分区时必须进行查找。
@Override
public void onPartitionsAssigned(Map<TopicPartition, Long> map, ConsumerSeekCallback consumerSeekCallback) {
// Do the seeks here using the `consumerSeekCallback` parameter.
}
在现代版本的spring-kafka中,除非您想在运行时执行任意查找(在初始查找之后),否则不需要使用ConsumerSeekAware
。您可以改用ConsumerAwareRebalanceListener
。