Quarkus所有REST服务部署就绪可达后如何执行自定义代码
StartupEvent 触发时仅完成了CDI上下文初始化,HTTP服务器尚未完成端口绑定、REST接口路由注册,这时候对外通知注册必然会出现对端调用失败的问题。你需要的全组件就绪触发点可按以下方案实现:
方案1:监听官方提供的应用启动完成事件(推荐)
Quarkus 2.x及以上版本提供了io.quarkus.runtime.ApplicationStartedEvent,该事件的触发时机是所有Quarkus扩展初始化完成、HTTP端口绑定成功、所有REST接口可正常对外提供服务,完全匹配你需要的「所有组件就绪」的时机。
代码示例:
import io.quarkus.runtime.ApplicationStartedEvent; import jakarta.enterprise.context.ApplicationScoped; import jakarta.enterprise.event.Observes; @ApplicationScoped public class ServiceRegister { public void onAllComponentReady(@Observes ApplicationStartedEvent event) { // 此处编写跨服务注册逻辑,所有对外接口已可正常访问 // doRegister(); } }
注意:如果你的注册逻辑是阻塞式操作(比如发HTTP请求、读写数据库),需要在方法上加
@io.smallrye.common.annotation.Blocking注解,避免阻塞Quarkus的IO事件循环线程引发异常。
方案2:HTTP层就绪精确监听
如果你只需要确认REST接口已经可以接收请求,不需要等待其他非Web组件初始化,可以监听io.quarkus.vertx.http.runtime.HttpServerStartupEvent,该事件在Vert.x HTTP服务器完成端口绑定、路由注册完成后立刻触发,时机比ApplicationStartedEvent稍早,但已经可以保证REST接口可正常访问。
代码示例:
import io.quarkus.vertx.http.runtime.HttpServerStartupEvent; import jakarta.enterprise.context.ApplicationScoped; import jakarta.enterprise.event.Observes; @ApplicationScoped public class ServiceRegister { public void onHttpReady(@Observes HttpServerStartupEvent event) { // HTTP服务已就绪,可执行注册逻辑 // doRegister(); } }
老版本Quarkus兼容方案
如果你使用1.x版本Quarkus,没有上述两个事件,可以通过实现QuarkusApplication主类的方式,在run方法中执行注册逻辑,run方法的执行时机就是应用完全启动完成后:
import io.quarkus.runtime.Quarkus; import io.quarkus.runtime.QuarkusApplication; import io.quarkus.runtime.annotations.QuarkusMain; @QuarkusMain public class MainApplication implements QuarkusApplication { @Override public int run(String... args) throws Exception { // 此处应用已完全就绪,执行注册逻辑 // doRegister(); // 阻塞等待应用关闭信号 Quarkus.waitForExit(); return 0; } }
踩坑提醒
不要使用@Observes @Initialized(ApplicationScoped.class) Object init这类CDI原生事件作为触发点,该事件触发时机和StartupEvent接近,同样早于HTTP服务就绪时间,会复现注册后接口不可用的问题。
内容的提问来源于stack exchange,提问作者JPS

