You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Quarkus异步请求在Vert.x事件循环线程执行时触发JNoSQL ConstructorBuilderSupplier实现缺失错误

Quarkus异步请求在Vert.x事件循环线程执行时触发JNoSQL ConstructorBuilderSupplier实现缺失错误

看起来你遇到了一个和Quarkus异步线程模型、JNoSQL服务加载相关的棘手问题,我来帮你拆解分析并给出解决方案:

问题核心分析

你的错误只在请求跑在vert.x-eventloop-thread时触发,而在ForkJoinPool.commonPool线程中完全正常,这说明线程上下文的差异是问题根源:

  • 当任务在ForkJoinPool执行时,JNoSQL能通过ServiceLoader找到LiteConstructorBuilderSupplier实现;
  • 但在Vert.x事件循环线程中,ServiceLoader无法加载到该服务实现,导致ConstructorBuilder.of()抛出NoSQLException。

为什么会出现线程上下文差异?

Quarkus的异步请求处理有特殊的线程模型:

  1. 你用CompletableFuture.supplyAsync(() -> {...})时,默认会使用JDK的ForkJoinPool,但Quarkus的Vert.x集成可能会在某些场景下把后续的回调逻辑调度回Vert.x事件循环线程(比如当CompletionStage的结果被Vert.x的响应处理器接管时)。
  2. Vert.x事件循环线程的类加载器上下文和Quarkus托管的工作线程(比如ForkJoinPool)不同,JNoSQL通过ServiceLoader加载的ConstructorBuilderSupplier服务,在Vert.x线程的类加载器中无法被找到——哪怕你已经正确打包了META-INF/services配置文件。

解决方案建议

1. 用Quarkus托管的线程池执行异步任务

Quarkus提供了自己的异步线程池,能保证线程上下文(包括类加载器、CDI上下文)的正确传播。你可以注入Quarkus的Executor来替代默认的ForkJoinPool:

@Path("project")
@Consumes({ MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_JSON })
@RolesAllowed("valid-user")
public class ProjectController {

    @Inject
    Executor quarkusExecutor; // 注入Quarkus托管的异步线程池

    @GET
    @Path("markers/{id}")
    public CompletionStage<Response> markers(@PathParam("id") String id) {
        // 指定用Quarkus线程池执行异步任务
        return CompletableFuture.supplyAsync(() -> {
            // 原有的业务逻辑代码
            ... doForEachMeasurement(project.get(), (p, m, g) -> { ... }
            ...
        }, quarkusExecutor);
    }
}

2. 避免在Vert.x事件循环线程中执行JNoSQL操作

Vert.x事件循环线程是IO线程,设计用来处理非阻塞IO操作,不适合执行需要CDI上下文或服务加载的阻塞业务逻辑。通过上述方式将JNoSQL相关的操作放到Quarkus托管线程池,就能避开这个问题。

3. 验证JNoSQL服务配置的打包正确性

确认你的应用打包后的jar中存在META-INF/services/org.eclipse.jnosql.mapping.metadata.ConstructorBuilderSupplier文件,且文件内容为:

org.eclipse.jnosql.mapping.lite.metadata.LiteConstructorBuilderSupplier

单元测试正常说明开发环境的类加载器能找到该配置,但运行时Vert.x线程的类加载器可能无法访问到,这点可以通过打印线程的上下文类加载器来验证:

// 在doForEachMeasurement方法开头添加
System.out.println("当前线程:" + Thread.currentThread().getName());
System.out.println("上下文类加载器:" + Thread.currentThread().getContextClassLoader());

对比ForkJoinPool和Vert.x线程的类加载器是否一致,如果不一致,说明Quarkus的类加载器隔离导致了服务加载失败。

4. 确认版本兼容性

检查Quarkus 3.23.0(注意:Quarkus稳定版最新为3.x系列,3.23可能是笔误,比如3.2.3)和JNoSQL 1.1.8的集成兼容性,是否有已知的线程上下文或服务加载问题,必要时升级到双方的最新兼容版本。

总结

这个问题本质是不同线程池的类加载器上下文差异导致JNoSQL的服务加载失败,通过使用Quarkus托管的线程池执行异步任务,确保线程上下文的一致性,就能解决这个错误。

内容来源于stack exchange

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.07 08:25:30