使用 CompletableFuture 时 UserTransaction jndi 查找失败

UserTransaction jndi lookup failed when using CompletableFuture

我有一个代码可以执行上下文查找以获取 UserTransaction JNDI 作为 ctx.lookup("java:comp/UserTransaction")

当我 运行 此代码而不使用 CompletableFuture 时,它按预期工作。

在异步线程中使用 CompletableFuture 时,出现异常提示 jndi 查找失败。

我尝试检查是否可以从 global 范围获取所需的 JNDI,但没有成功。

问题似乎是 JNDI 上下文没有传播到异步线程,所以当 CompletionStage 尝试执行 JNDI 查找时,它没有上下文,所以它不知道哪个组件它在里面,因此失败了。

https://openliberty.io/docs/21.0.0.8/microprofile-context-propagation.html 上有关于上下文传播以及如何在 Open Liberty(它是 WebSphere Liberty 的基础产品)中有效执行它的非常详细的解释 - 我强烈建议您阅读它。

某些 Java/Jakarta/MicroProfile API 将允许您指定用于异步操作的异步服务 (ExecutorService)。如果可能,您可以向它传递一个 ManagedExecutorService 的实例,它应该将上下文(如 JNDI、安全性、类加载等)传播到异步线程。否则,您可能需要在构建 CompletionStage.

时指定托管执行程序服务

CompletableFutures 通常 运行 在 JDK 的 ForkJoinPool 而不是应用程序服务器管理的线程上,因此无法访问应用程序服务器提供的服务。 MicroProfile Context Propagation(在 Liberty 中可用)通过为您提供一种在 Liberty 线程池上创建 运行 并可以访问应用程序组件上下文的 CompletableFutures 的方法来解决这个问题。

在server.xml,

<featureManager>
  <feature>mpContextPropagation-1.2</feature> <!-- 1.0 is also valid -->
  <feature>jndi-1.0</feature>
  <feature>jdbc-4.2</feature> <!-- or some other feature that participates in transactions -->
  ... other features
</featureManager>

在您的申请中,

import org.eclipse.microprofile.context.ManagedExecutor;
import org.eclipse.microprofile.context.ThreadContext;
...
ManagedExecutor executor = ManagedExecutor.builder()
                           .propagate(ThreadContext.APPLICATION)
                           .build();

CompletableFuture<?> f = executor.supplyAsync(() -> {
    UserTransaction tx = InitialContext.doLookup("java:comp/UserTransaction");
    ...
});

...
executor.shutdown();

如果您不想构建新的 ManagedExecutor,Liberty 还允许您将 EE Con​​currency ManagedExecutorService 转换为 ManagedExecutor 并使用它。例如,

ManagedExecutor executor = InitialContext.doLookup("java:comp/DefaultManagedExecutor");

还应注意,使用 ManagedExecutor,应用程序上下文可用于依赖阶段和初始阶段,如果您愿意,可以在依赖阶段执行查找,例如以下阶段:

executor.supplyAsync(supplier).thenApplyAsync(v -> {
    UserTransaction tx = InitialContext.doLookup("java:comp/UserTransaction");
    ...
});