首页 > 解决方案 > quarkus: IllegalStateException: 您试图在 IO 线程上执行阻塞操作。这是不允许的,因为阻塞了 IO 线程

问题描述

我无法理解 quarkus 的一件事。我将 JPA 与 Oracle 一起使用。所以我有错误 IllegalStateException: 你试图在 IO 线程上执行阻塞操作。这是不允许的,因为阻塞了 IO 线程,我在 Quarkus 文档中查看了如何在没有这个困难的情况下进行 JPA 调用。但所有示例和文档都使用 PostgreSQL 或 MariaDB 和响应式客户端。但我还没有找到任何经典的 JDBC 客户端。

我找到了一个部分有效的解决方案。

Uni.cretaFrom().Items(() -> MyBlokingIOCall());

事实上,我不再有例外。但是 MyBlokingIOCall 方法可以引发异常。我想我可以使用 Uni 的 onFailure 但我们不能将引发异常的方法传递给

Uni.cretaFrom().Items

事实上,这个方法有一个供应商作为参数,因此必须捕获异常。在这个解决方案中使用 Uni 的 onFailure 是不可能的。如果我在命令模式下使用当前代码

try {
   Response.ok (myService ());
} catch (throwable e) {
   Response.status (555, e.getMessage ());
}

我徒劳地试图以反应形式做到这一点,但我没有找到解决方案。我没有找到任何帮助。我想象过类似的东西。

Uni.createFrom().Items(() -> myService())
.onItem().apply(data -> Response.ok(data))
.onFailure().apply(err -> Response.status(555, err.getMessage()))

但这会导致编译错误。实际上 myService 方法不能在 Supplier 中使用,因为它会引发异常。因此必须将其捕获。但是后来我们不再进入 Uni 的 onFailure 并且我们无法追踪我们捕获的错误。

我认为我想太多关于穿着我的命令式代码而不是不同的想法。

但是我无论如何都找不到看起来像这样的文档或示例。我想有一种做事的方式(如果不是 Quarkus 就不会存在)。我认为当你用正确的方法考虑它时,你必须找到文档,但是当你不知道去哪里时,它就更复杂了。我没有找到它,因为我不知道我在寻找什么。

我想我必须封装产生 Uni 或 Multi 的 JPA 调用,该调用由将实体转换为 DTO 的处理器消耗,然后将其传输到将 DTO 转换为响应的资源 Rest 层。JPA 调用也必须能够在处理器和资源层产生错误

因此,有必要在每个步骤中捕获这些错误以通过 Uni 或 Multi 传播它们

但是怎么做呢?

标签: javaquarkusreactive-streamsmutiny

解决方案


通过简单地提供lambda实现(或方法引用)作为方法调用参数,这是一种已知的lambda限制。

同时,可以通过在预期的Functional Interface周围实现扩展来简单地解决它,在您的情况下Supplier<T>,它将捕获任何 **checked** 异常并抛出未经检查的异常:

/**
 * A Supplier sub-interface that catches any thrown exception
 * and translates to an unchecked one.
 *
 * <p>This is a functional interface whose functional method is
 * {@link #getChecked()}.
 */
@FunctionalInterface
public interface CheckedSupplier<T> extends Supplier<T> {

    @Override
    default T get() {
        try {
            return getChecked();
        } catch (final Exception e) {
            // Your common exception handling logic here..
            throw new RuntimeException(e);
        }
    }

    /**
     * Gets a result.
     *
     * @return a result
     * @throws Exception
     */
    T getChecked() throws Exception;
}

请注意,功能接口签名不再是#get()而是#getChecked()。但这对编译器没有任何影响,它将尝试根据预期的签名检查功能签名,即:

返回 T 类型对象的方法

然后,您可以在任何需要 a (或类似)的地方使用显式转换来简单地使用新CheckedSupplier接口:Supplier<T>

Uni.createFrom().item((CheckedSupplier<DataType>) MutinyTest::findOne)
      .onItem()
      .apply(i-> Response.ok(i))
      .onFailure()
      .apply(e-> Response.status(555, e.getMessage()));

推荐阅读