EJB中的Thread.sleep()

Ari*_*iod 19 ejb java-ee

我知道搞乱EJB中的线程是一个很大的禁忌,但我想就如何处理这种情况征求意见.我的EJB正在调用外部Web服务,有时可能会返回"忙"状态.当发生这种情况时,我想等待一段时间,然后使用与以前相同的数据重新提交请求.

实现这个的最佳方法是什么?

Tom*_*icz 13

EJB 3.1带来了一个可以利用的新@Asynchronous 功能:

@Asynchronous
@TransactionAttribute(NOT_SUPPORTED)
public Future<WebServiceResult> callWebService(int retries) {
    WebServiceResult result = webService.call();

    if (!result.equals(BUSY)) {
        return result;
    }

    if (retries <= 0) {
        throw new TooBusyException();
    }

    try {
        Thread.sleep(1000);
    } catch (InterruptedException e) {
        Thread.currentThread().interrupt();
    }

    return callWebService(retries - 1);
}
Run Code Online (Sandbox Code Playgroud)

然后简单地通过以下方式呼叫您

Future<WebServiceResult> result = yourEJB.callWebService(1);

// Can do some interesting stuff here.
// ...
// ...

result.get(2, SECONDS);  // Block for up to 2 seconds.
Run Code Online (Sandbox Code Playgroud)

如您所见,您可以免费获得可配置的重试次数和超时.

这与仅仅打电话有Thread.sleep()什么不同?返回Future更明确,更易于管理.我也不认为那Thread.sleep()是有害的.唯一的问题是这个EJB实例现在可以更长时间被其他客户端重用.随着Future异步调用里面发生一些其他的EJB和线程池.至于Thread#interrupt()catch块内部的重要性,请参考为什么在捕获任何InterruptException时调用Thread.currentThread.interrupt()?

另一个想法:使用方面调用Web服务,捕获BusyException一次并重试.

  • 它比在被调用的EJB中使用Thread.sleep()更好吗?它仍然违反了规范 - 它只是更明确,但你阻止了2个EJB实例 - 生成(异步)实例和调用实例. (3认同)

Ósc*_*pez 11

EJB限制常见问题解答中,它明确指出了您

不应该创建或管理线程

将一个线程置于睡眠状态算作"管理"它.

在您的情况下,当Web服务返回"忙"状态时,您可以安排作业在稍后的时间点重试发送消息,例如使用Quartz Scheduler.执行将在那里结束,并且应该将任何进一步的处理委托给作业调度程序.

  • 您还可以使用内置的Java EE计时器支持. (6认同)