【问题标题】:UserTransaction jndi lookup failed when using CompletableFuture使用 CompletableFuture 时,UserTransaction jndi 查找失败
【发布时间】:2021-08-31 20:00:06
【问题描述】:

我有一个代码可以进行上下文查找以将 UserTransaction JNDI 设为 ctx.lookup("java:comp/UserTransaction")

当我在不使用CompletableFuture 的情况下运行此代码时,它会按预期工作。

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

我尝试检查是否可以从global 范围内获得所需的 JNDI,但没有运气。

【问题讨论】:

    标签: java ejb jndi websphere-liberty completable-future


    【解决方案1】:

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

    在 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");
        ...
    });
    

    【讨论】:

    • 不,根据 ManagedExecutor JavaDoc,ManagedExecutor 是“一个容器管理的执行器服务,它创建 CompletableFuture 的实例,它作为默认的异步执行工具支持 CompletableFuture 本身以及从它创建的所有从属阶段,以及从那些创建的所有从属阶段,等等。”因此,您不提供任何执行者。所有异步完成阶段操作都将在 ManagedExecutor 上运行,而不是在 JDK 的非托管 ForkJoin 线程上运行。
    • 关于supplier的第二个问题,你可以放任何你想要的东西。如果您愿意,可以使用第一个示例的 supplyAsync 中的供应商。我只是想表明,如果您从中创建 CompletableFuture,ManagedExecutor 将涵盖每个相关阶段(supplyAsync、thenApplyAsync 和所有其他阶段)。然而,如果您只是将托管执行程序服务放入 *Async 执行程序参数中,您将获得不确定的行为,具体取决于之前的 CompletionStage 在执行程序上调用提交时碰巧运行的位置。
    • 感谢您的反馈。我将更新答案,将该示例分成两部分,每部分都说明了我试图在此处传达的相应信息。
    【解决方案2】:

    问题似乎是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 时指定托管执行器服务。

    【讨论】:

      猜你喜欢
      • 2019-03-19
      • 2013-06-29
      • 2018-09-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-11-24
      • 2011-07-24
      相关资源
      最近更新 更多