@KafkaListener 生命周期管理
为 @KafkaListener 注解创建的监听器容器不是应用上下文中的 bean。相反,它们被注册到一个类型为 KafkaListenerEndpointRegistry 的基础架构 bean 中。该 bean 由框架自动声明并管理这些容器的生命周期;它会自动启动任何将 autoStartup 设置为 true 的容器。由所有容器工厂创建的所有容器必须处于相同的 phase。有关更多信息,请参阅监听器容器自动启动。你可以使用 registry 以编程方式管理生命周期。启动或停止 registry 将启动或停止所有已注册的容器。或者,你可以使用其 id 属性获得对单个容器的引用。你可以在注解上设置 autoStartup,它会覆盖配置到容器工厂中的默认设置。你可以从应用上下文(例如通过自动装配)获得对该 bean 的引用,以管理其已注册的容器。以下示例展示了如何这样做:
@KafkaListener(id = "myContainer", topics = "myTopic", autoStartup = "false")
public void listen(...) { ... }
@Autowired
private KafkaListenerEndpointRegistry registry;
...
this.registry.getListenerContainer("myContainer").start();
...
registry 只维护它所管理的容器的生命周期;声明为 bean 的容器不由 registry 管理,可以从应用上下文中获取。可以通过调用 registry 的 getListenerContainers() 方法获得一个受管容器的集合。版本 2.2.5 添加了一个便捷方法 getAllListenerContainers(),它返回所有容器的集合,包括由 registry 管理的容器和声明为 bean 的容器。返回的集合将包括任何已初始化的原型 bean,但它不会初始化任何惰性 bean 声明。
在应用上下文刷新之后注册的端点将立即启动,无论其 autoStartup 属性如何,以遵守 SmartLifecycle 契约——在该契约中,autoStartup 仅在应用上下文初始化期间被考虑。延迟注册的一个例子是:一个在原型作用域中带有 @KafkaListener 的 bean,其实例在上下文初始化之后才被创建。从版本 2.8.7 开始,你可以将 registry 的 alwaysStartAfterRefresh 属性设置为 false,此后容器的 autoStartup 属性将决定是否启动该容器。
从 KafkaListenerEndpointRegistry 获取 MessageListenerContainer
KafkaListenerEndpointRegistry 提供了用于检索 MessageListenerContainer 实例的方法,以适应一系列管理场景:
所有容器:对于覆盖所有监听器容器的操作,使用 getListenerContainers() 来检索一个全面的集合。
Collection<MessageListenerContainer> allContainers = registry.getListenerContainers();
按 ID 指定容器:要管理单个容器,getListenerContainer(String id) 支持按其 id 检索。
MessageListenerContainer specificContainer = registry.getListenerContainer("myContainerId");
动态容器过滤:在版本 3.2 中引入的两个重载 getListenerContainersMatching 方法支持对容器进行精细选择。一个方法接收一个 Predicate<String> 作为基于 ID 过滤的参数,另一个方法接收一个 BiPredicate<String, MessageListenerContainer> 作为用于更高级条件(可包括容器属性或状态)的参数。
// Prefix matching (Predicate<String>)
Collection<MessageListenerContainer> filteredContainers =
registry.getListenerContainersMatching(id -> id.startsWith("productListener-retry-"));
// Regex matching (Predicate<String>)
Collection<MessageListenerContainer> regexFilteredContainers =
registry.getListenerContainersMatching(myPattern::matches);
// Pre-built Set of IDs (Predicate<String>)
Collection<MessageListenerContainer> setFilteredContainers =
registry.getListenerContainersMatching(myIdSet::contains);
// Advanced Filtering: ID prefix and running state (BiPredicate<String, MessageListenerContainer>)
Collection<MessageListenerContainer> advancedFilteredContainers =
registry.getListenerContainersMatching(
(id, container) -> id.startsWith("specificPrefix-") && container.isRunning()
);
利用这些方法,可以在你的应用程序中高效地管理和查询 MessageListenerContainer 实例。