1

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

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

@Stateful
public class EmailEJB {

  @Asynchronous
  public Future<Integer> sendMails() {
    for (int i=0; i<mails.size; i++) {
      sendMail(mails[i])
      // i want to return the progress without returning ;)
      return new AsyncResult<Integer>(i)
    }
  }
}

//Just for the completeness... from outside, i'm accessing the progress like this:
Future<Integer> progress = emailEJB.sendEmails();
Integer currentvalue = progress.get();

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

4

3 回答 3

4

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

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

@Singleton @LocalBean @Startup
public class ProgressEJB {
  private HashMap<String, Integer> progressMap = new HashMap<String, Integer>
  // getters and setters
}

这个 hashmap 应该将 SessionId(一个字符串)映射到一个整数值(进度 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<mails.size; i++) {
    sendMail(mails[i])
    progress.getProgressMap().put(sessionId, (i / mails.size) * 100)
  }
  progress.getProgressMap().remove(sessionId);
}

sessionId 在调用函数时来自我的托管(焊接)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 个用户进行了测试,似乎有效。

于 2010-07-29T14:34:33.867 回答
0

我在这里也只看到了一个@Singleton 解决方案。但这意味着Housekeeping in ProgressEJB 的需要。例如,需要一些努力来从 Hashmap 中修剪旧会话。

于 2013-09-04T07:58:10.163 回答
-1

另一种解决方案在 是否有任何方法可以知道 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<mails.size; i++) {
        sendMail(mails[i])
        context.setProgress((i / mails.size) * 100)
      }
      context.setRunning(false);
    }
}

保存进度的上下文对象。

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();
  }
  ....
}
于 2017-10-23T11:59:03.167 回答