我正在尝试实现一个异步执行可调用对象的通用类,但我不确定语义。
@Component
public class MyCallerImpl implements MyCaller {
@Async
@Override
public <T> Future<T> runAsync(Callable<T> callable) throws Exception {
return new AsyncResult<T>(callable.call());
}
}
基本上,该组件使用 @Async 注释从任何可调用的异步执行任意操作。
我不确定方法签名的 throws 子句中的异常。
一个 Junit 测试:
@ContextConfiguration("classpath:test-config.xml")
@RunWith(SpringJUnit4ClassRunner.class)
public class RunnerTest{
@Resource(name="myCallerImpl")
private MyCaller myCaller;
@Test
public void testException(){
final Callable<String> callable = new Callable<String>(){
@Override
public String call() throws Exception{
throw new MyException("foobar");
}
};
try
{
final Future<String> future = myCaller.runAsync(callable); // this can throw Exception due to Callable.call()
future.get(); // this can throw InterruptedException and ExecutionException
}
catch (final InterruptedException ie)
{
// do someting
}
catch (final ExecutionException ee)
{
// we want to check the cause
final Throwable cause = ee.getCause();
assertTrue(cause instanceof MyException);
}
catch (final Exception e)
{
// Not sure what to do here.
// Must be caught as it is declared to
// be thrown from the MyCaller.runAsync() method
// but nothing will really ever get here
// since the method is @Async and any exception will be
// wrapped by an ExecutionException and thrown during Future.get()
fail("this is unexpected);
}
我的问题是如何处理 MyCallerImpl.runAsync() 的 throws 子句中声明的异常?
我声明它的唯一原因是因为我调用可调用对象的方式。最初我在异步方法中有以下内容:
FutureTask<T> futureTask = new FutureTask<T>(callable);
futureTask.run();
return futureTask;
但是,当从该实例中的可调用对象抛出异常时,它会在 ExecutionException 中包装两次,第一次是 FutureTask.run() 最终被调用时 FutureTask.Sync.innerRun() 捕获异常并调用 innnerSetException() 和第二次 AsyncExecutionIntercepter 通过 Future.get() 从 Future 获取结果,最终再次检查是否有异常并抛出一个新的 ExecutionException 包装在 innerRun() 中捕获的 ExecutionException
我还尝试在方法中执行以下操作:
FutureTask<T> futureTask = new FutureTask<T>(callable);
return futureTask;
我认为自从 AsyncExecutionInterceptor 调用 Future.get() 后,会立即调用可调用对象,但事实并非如此。它只是挂在 FutureTask.acquireSharedInterruptibly() 上并且永远不会返回。
也许我在这里过头了。它现在如何使用可调用文件进行设置,但我宁愿没有方法签名声明抛出异常。
有什么建议吗?我应该忘记这种使用可调用对象进行异步调用的通用方式吗?