Vert.x应用在Eclipse中可正常关闭,Jar包运行后无法自动退出
Vert.x程序Jar包运行后无法自动退出的解决方案
问题描述
本地Eclipse环境运行时,程序可正常执行并自动关闭;但通过Maven打包为Jar包后,执行java -jar application.jar命令,程序完成请求并输出响应后,无法自动终止,需手动中断。已尝试在onSuccess、onFailure、部署回调及stop()方法中调用System.exit(0),问题仍未解决。
涉及代码
Main类代码
public static void main(String[] args) { Vertx vertx = Vertx.vertx(); vertx.deployVerticle(new MainVerticle(), whenDeployed -> { vertx.close(); // System.exit(0); }); }
MainVerticle类代码
public class MainVerticle extends AbstractVerticle { private static final ObjectMapper mapper = new ObjectMapper(); private static final Logger log = LoggerFactory.getLogger(MainVerticle.class); @Override public void start(Promise<Void> startPromise) throws Exception { Configuration config = null; try(FileInputStream fin = new FileInputStream("/opt/vertex-proxy/config.json")){ config = mapper.readValue(fin, Configuration.class); } catch(Exception e) { log.error("Invalid configuration\n{}", e.getCause()); } log.info("Started application\n"); ProxyOptions proxyOptions = new ProxyOptions() .setHost(config.getProxy().getIp()) .setPort(config.getProxy().getPort()); WebClientOptions options = new WebClientOptions().setUserAgent("Yash client") .setProtocolVersion(HttpVersion.HTTP_2).setHttp2ClearTextUpgrade(false) .setConnectTimeout(config.getTarget().getConnectionTimeout()) .setProxyOptions(proxyOptions); WebClient client = WebClient.create(vertx, options); HttpRequest<Buffer> req = client.get(config.getTarget().getPort(), config.getTarget().getIp(), config.getTarget().getUri()); req.send().onSuccess(response -> { log.info("Received response with status code: " + response.statusCode()); log.info("Response:\n" + response.bodyAsString()); startPromise.complete(); }).onFailure(err -> { log.error("Something went wrong\n" + err.getCause()); startPromise.complete(); }); } @Override public void stop() throws Exception { System.out.println("\nStopping application"); } }
解决思路与方案
核心问题分析
- Vert.x的
vertx.close()是异步操作,原代码未等待关闭完成就结束主线程,导致事件循环线程仍在运行。 - WebClient未显式关闭,持有底层连接资源,阻止JVM退出。
- 配置读取失败时未正确处理
Promise,导致Verticle启动流程未完成,Vertx无法触发关闭逻辑。
具体调整步骤
等待Vertx关闭完成再退出
修改Main类的部署回调,监听vertx.close()的完成事件,确保完全关闭后再调用System.exit():vertx.deployVerticle(new MainVerticle(), whenDeployed -> { vertx.close(closeResult -> { System.exit(closeResult.succeeded() ? 0 : 1); }); });显式关闭WebClient释放资源
在请求成功或失败的回调中,关闭WebClient避免资源泄漏:req.send().onSuccess(response -> { log.info("Received response with status code: " + response.statusCode()); log.info("Response:\n" + response.bodyAsString()); client.close(); startPromise.complete(); }).onFailure(err -> { log.error("Something went wrong\n" + err.getCause()); client.close(); startPromise.complete(); });修复配置读取异常的Promise处理
配置读取失败时,标记startPromise为失败并触发Vertx关闭,避免流程阻塞:catch(Exception e) { log.error("Invalid configuration\n{}", e.getCause()); startPromise.fail(e); vertx.close(); return; }添加Vertx退出钩子兜底
在Main类中设置退出处理器,确保事件循环全部结束后触发JVM退出:Vertx vertx = Vertx.vertx(); vertx.setExitHandler(exitCode -> { System.exit(exitCode); });
优化后的完整逻辑建议
将Vertx关闭逻辑移至Verticle的请求完成回调中,确保任务结束后才触发关闭,避免提前终止:
// MainVerticle的start方法中,请求完成后 req.send().onSuccess(response -> { // ... 日志输出 ... client.close(); startPromise.complete(); vertx.close(); // 任务完成后主动关闭Vertx }).onFailure(err -> { // ... 日志输出 ... client.close(); startPromise.complete(); vertx.close(); });
内容的提问来源于stack exchange,提问作者Dominator_007
相关产品推荐
相关产品推荐

