为什么javax.ejb.AsyncResult.isDone总是抛出异常?

时间:2014-04-02 11:48:44

标签: java java-ee asynchronous future

我认为我误解了java ee异步方法调用。我正在遵循这位官员tutorial的想法。对于void方法,它很好,但我希望我的异步方法返回一个值:

@Asynchronous
public Future<String> processPayment(Order order) {
    ...
    String status = ...;
    return new AsyncResult<String>(status);
}

我在后台有很多这样长时间运行的任务,所以我收集List<Future<String>>并循环遍历它们以检查任务是否完成。我按

进行检查
for(Future<String> future: listOfFutures) {
    if(future.isDone())
       // do something
}

但是当调用方法IllegalStateException:"Object does not represent an acutal Future"时,代码会因AsyncResult.isDone()而失败。

那么,我读了this,这让我非常困惑:官方教程说“使用AsyncResult.isDone()”检查异步方法的状态,而官方的javadoc说< strong>“不敢使用AsyncResult.isDone()”。

我知道我可以将FutureTask<T>Callable<T>一起使用,但这是java se部分。

如果可以使用 java ee异步方法调用,你能解释一下吗?

谢谢!

P.S。我正在使用Glassfish 3.1.2和EJB 3.1

3 个答案:

答案 0 :(得分:1)

所以,你的问题是“是否可以使用java ee异步方法调用?” 答案是。你问题中的两小部分代码是正确的。但是,要完全诊断出您的情况出了什么问题,我们可能需要查看更多代码。

可能是您没有正确使用注释。可以在这里阅读如何使用的超短代码示例: https://tomee.apache.org/examples-trunk/async-methods/README.html

该示例的重要信息是您的异步方法必须声明为 Singleton 无状态 bean(让我们称之为容器bean ),以及我们可以调用客户端的另一个bean(或Servlet,或POJO,可以访问正确的JNDI上下文,如上面的链接)调用容器bean 。所以要明确的是, for 循环位于客户端中。那么你的AsyncResult就会表现得像你想要的那样。

如果您仔细阅读了链接的javadoc,则说:

  

容器将检索构造函数中指定的值,并使其可供客户端使用。

  

应用程序

不应调用任何实例方法

这意味着AsyncResult类是一种“哑包装”,可以让你轻松实现界面,但不应该用于“真实”。

请注意,当您实现EJB或位于EJB容器之外时,使用ExecutorService是执行异步调用的方法。对您有用的事实使我直接引用容器类,而不是通过@EJB注释或JNDI查找。

答案 1 :(得分:0)

如果使用Spring Framework,请使用

org.springframework.scheduling.annotation.AsyncResult

代替

javax.ejb.AsyncResult

答案 2 :(得分:-1)

@Holger在某种意义上指出了正确的方向:在这种情况下,我的问题是FutureAsyncResult的实施。事实证明这很有趣。我查看了AsyncResult类代码,这就是我所看到的:

public boolean cancel(boolean mayInterruptIfRunning)
{
  throw new IllegalStateException("Object does not represent an acutal Future");
}

public boolean isCancelled()
{
  throw new IllegalStateException("Object does not represent an acutal Future");
}

public boolean isDone()
{
  throw new IllegalStateException("Object does not represent an acutal Future");
}

所以它解释了为什么我一直都有这个例外。

我的解决方法是将java.util.concurrent.ExecutorService.submit(new MyCallable<MyClass>(myClassInstance))作为java.util.concurrent.Future<MyClass>实施返回。在按预期工作后。