使用 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 Concurrency ManagedExecutorService 转换为 ManagedExecutor 并使用它。例如,
ManagedExecutor executor = InitialContext.doLookup("java:comp/DefaultManagedExecutor");
还应注意,使用 ManagedExecutor,应用程序上下文可用于依赖阶段和初始阶段,如果您愿意,可以在依赖阶段执行查找,例如以下阶段:
executor.supplyAsync(supplier).thenApplyAsync(v -> {
UserTransaction tx = InitialContext.doLookup("java:comp/UserTransaction");
...
});
我有一个代码可以执行上下文查找以获取 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 Concurrency ManagedExecutorService 转换为 ManagedExecutor 并使用它。例如,
ManagedExecutor executor = InitialContext.doLookup("java:comp/DefaultManagedExecutor");
还应注意,使用 ManagedExecutor,应用程序上下文可用于依赖阶段和初始阶段,如果您愿意,可以在依赖阶段执行查找,例如以下阶段:
executor.supplyAsync(supplier).thenApplyAsync(v -> {
UserTransaction tx = InitialContext.doLookup("java:comp/UserTransaction");
...
});