公开@Asynchronous函数的当前进度以在View中使用

在我的JEE6-App(在Glassfish 3.0.1上运行)中,我有一个EmailEJB,它必须发送大量邮件。 邮件是异步发送的,所以它用新的EJB3.1 @Asynchronous注释,让它在一个单独的Thread中运行。 现在我想让用户了解该方法的当前状态:已发送了多少封邮件?

异步发送邮件工作正常,但我无法弄清楚如何从外部访问进度。 似乎我的做法是非常错误的,但不知何故它必须是可能的(也许是另一种方法)。 这就是我的EmailEJB目前的样子(它的伪代码,但解释了我想要的):

@Stateful public class EmailEJB { @Asynchronous public Future sendMails() { for (int i=0; i<mails.size; i++) { sendMail(mails[i]) // i want to return the progress without returning ;) return new AsyncResult(i) } } } //Just for the completeness... from outside, i'm accessing the progress like this: Future progress = emailEJB.sendEmails(); Integer currentvalue = progress.get(); 

如何在异步函数中返回当前进度,而不用返回取消它? 如何向用户显示函数内循环的进度? 我需要另一种异步方法吗? 任何提示?

没有人? 好的,这是我的解决方案。 我不确定这是一个很大的解决方法,还是只是一种完成这项工作的方法。

由于@Asynchronous方法无法访问Session上下文,因此也没有会话Bean(至少我不知道如何,我总是得到ConcurrentModificationErrors或类似的)我创建了一个包含HashMap的Singleton ProgressEJB:

 @Singleton @LocalBean @Startup public class ProgressEJB { private HashMap progressMap = new HashMap // getters and setters } 

此hashmap应将SessionId(String)映射到Integer值(进度0-> 100)。 因此,用户会话与进度相关联。 在我的EmailEJB中,我正在注入此ProgressEJB,并且在我的@Asynchronous方法中,每次发送电子邮件时我都会增加值:

 @Stateful @LocalBean public class EmailEJB { @Inject private ProgressEJB progress; // Mail-Settings ... @Asynchronous public void sendEmails(user:User, message:Message, sessionId:String) { progress.progressMap.put(sessionId, 0); for (int i=0; i 

在调用函数时,sessionId来自我的Managed(Weld)Bean:

 @SessionScoped @Named public class EmailManager { @Inject private ProgressEJB progress; @Inject private FacesContext facesContext; private String sessionId; @PostConstruct private void setSessionId() { this.sessionId = ((HttpSession)facesContext.getExternalContext().getSession(false)).getId(); } public Integer getProgress() { if (progress.getProgressMap().get(sessionId) == null) return 100; else return progress.getProgressMap().get(sessionId); } } 

现在我可以通过Ajax Polling从我的JSF视图访问EmailManager的进度,告诉用户已经发送了多少封邮件。 刚刚用2个用户测试过,似乎工作正常。

我在这里也只看到了@Singleton解决方案。 但这意味着需要管理进步EJB。 例如,需要一些努力来从Hashmap中删除旧会话。

有没有办法知道EJB异步进程的进展?

此解决方案不需要有状态Bean。

 @Stateless public class EmailEJB { // Mail-Settings ... @Asynchronous public void sendEmails(User user, Message message, WorkContext context) { progress.progressMap.put(sessionId, 0); for (int i=0; i 

Context-Object,它保存进度。

 public class WorkContext { //volatile is important! private volatile Integer progress = 0; private volatile boolean running = false; // getters & setters } 

用法非常简单。

 @SessionScoped @Named public class EmailManager { @Inject private EmailEJB emailEJB; private WorkContext workContext; public void doStuff() { workContext = new WorkContext(); emailEJB.sendEmails(user, message, workContext) } public Integer getProgress() { return workContext.getProgress(); } .... }