gpt4 book ai didi

jsf - 如何在@Asynchronous 方法中正确使用CDI?

转载 作者:行者123 更新时间:2023-12-04 02:03:38 24 4
gpt4 key购买 nike

我有一个 JSF 2 应用程序(在 JBoss AS 7.1 上运行),当用户单击页面中的按钮时,它必须启动一个漫长的过程。这个想法是要有一个不阻塞的交互,这样用户就可以等待并查看结果,或者只是关闭页面,稍后再回来查看它的进展情况或结果(如果该过程已经结束)。

流程本身在以下(简化的)类中编码:

@Stateless
@LocalBean
@ApplicationScoped
public class MyProcessManager {
@Inject
private ProcessHelper processHelper;

@Asynchronous
public void start(final ProcessParameters parameters) {
// the process...
}
}

这样一个类被标记为 @ApplicationScoped 因为所有正在运行的进程(对于所有用户)都由它保存。因此,当单击按钮时,辅助 bean 设置一些参数并调用异步方法 start()

在进程尝试使用 processHelper 之前一切正常,它运行大量 Hibernate 查询以继续进程的持久性部分。当调用 processHelper 的第一个方法时,出现以下异常:

WELD-001303: No active contexts for scope type javax.enterprise.context.RequestScoped

作为附加信息,永远不会命中此类方法内的断点。

发生了什么以及如何解决它?

最佳答案

异常表明 ProcessHelper@RequestScoped

@Asynchronous 被调用时,一个全新的独立线程被生成,它由 HTTP servlet 容器控制。在该线程的上下文中,因此无法在任何地方进行 HTTP 请求或 HTTP session 。您只能使用@ApplicationScoped,不能使用@RequestScoped,更不用说@SessionScoped

至于ProcessManager 本身,组合@Stateless @ApplicationScoped 没有意义。你很可能真的想要一个 @javax.ejb.Singleton .额外的好处是它是有状态的,因此您可以将过程结果作为实例变量保存在那里。

您提到 ProcessHelper 反过来运行一些数据库查询。这意味着它应该在事务中运行。在那种情况下,您应该使它成为完全有值(value)的 EJB 而不是 CDI 托管 bean。因此,也将 ProcessHelper 设为 @Stateless,或者将所有 DB 交互作业移动到 ProcessManager EJB 中。这也是可能的。

所以,总而言之,应该这样做:

<h:form>
<h:commandButton value="Start" action="#{processBacking.start}" />
</h:form>
<p>
Result (manually refresh page to check): #{processBacking.result}
</p>

@Named
@RequestScoped
public class ProcessBacking {

@Inject
private ProcessManager processManager;

public void start() {
// ...
processManager.start(parameters);
}

public ProcessResult getResult() {
return processManager.getResult();
}

// ...
}

@Singleton
@ConcurrencyManagement(ConcurrencyManagementType.BEAN)
public class ProcessManager {

private ProcessResult result;

@Inject
private ProcessHelper helper;

@Asynchronous
@TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED)
public void start(ProcessParameters parameters) {
ProcessResult result = runSomeLongRunningNonTransactionalProcess(parameters);
this.result = helper.persist(result);
}

public ProcessResult getResult() {
return result;
}

}

@Stateless
public class ProcessHelper {

@PersistenceContext
private EntityManager entityManager;

@TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
public ProcessResult persist(ProcessResult result) {
entityManager.persist(result);
return result;
}

}

请注意,@Singleton 默认情况下是读/写锁定的。因此,在 start() 完成之前,您不能调用 getResult()。因此 ConcurrencyManagementType.BEAN,这意味着它是未锁定的,因此基本上调用者自己负责并发管理。只要该进程仍在运行,您就可以继续刷新页面。

另见:

关于jsf - 如何在@Asynchronous 方法中正确使用CDI?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45545743/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com