Quarkus响应式应用自定义Jackson反序列化器如何从数据库加载实体
错误根因
你当前的反序列化操作运行在Vert.x事件循环线程上,Quarkus严格禁止在事件循环线程执行任何阻塞逻辑,你调用await().indefinitely()属于阻塞调用,因此触发了该异常。
可行解决方案
方案1:给请求端点添加@Blocking注解(改造成本最低)
如果你的反序列化是在REST接口接收参数时触发的,直接在对应端点方法上加@Blocking注解,Quarkus会把整个请求处理流程调度到工作线程执行,天然允许阻塞操作,不需要修改现有反序列化器代码:
import io.smallrye.common.annotation.Blocking; import javax.ws.rs.POST; import javax.ws.rs.Path; @Path("/my-endpoint") public class MyController { @POST @Blocking public MyResponse handle(MyType myType) { // 原有业务逻辑 } }
方案2:反序列化器内切换线程再阻塞(不改动上层代码)
如果没法给端点加注解,可以在反序列化器内把数据库查询操作切换到工作线程池再执行阻塞等待,被阻塞的是工作线程不会触发规则校验:
@Override public MyType deserialize( JsonParser jsonparser, DeserializationContext context) throws IOException { MyTypeService service = (MyTypeService) context .findInjectableValue("myTypeServiceBean", null, null); String info = jsonparser.getText(); // 先切换到工作线程池再执行阻塞等待 return service.find("info = :info", Parameters.with("info", info)) .runSubscriptionOn(Infrastructure.getDefaultWorkerPool()) .await().indefinitely(); }
注:需要引入Quarkus内置类io.quarkus.vertx.core.runtime.Infrastructure。
方案3:IO操作移出反序列化器(符合响应式规范的最优实现)
反序列化器的设计定位是做纯内存的数据格式转换,不建议承载IO类重操作,你可以调整逻辑规避这个问题:
- 给
MyType新增临时的info字段,反序列化阶段只把JSON中的info值存入该字段,不做数据库查询 - 反序列化完成后的业务层,正常异步调用
service.find方法组装完整的MyType实例
这种方式完全没有阻塞操作,符合响应式编程规范,性能最优。
内容的提问来源于stack exchange,提问作者quarkus_coder
相关产品推荐
相关产品推荐

