我正在尝试实现一个异步执行可调用的泛型类,但我不确定语义。
@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子句中声明的异常?
我声明它的唯一原因是因为我调用callable的方式。最初我在异步方法中有以下内容:
FutureTask<T> futureTask = new FutureTask<T>(callable);
futureTask.run();
return futureTask;
但是当从该实例中的callable抛出异常时,它会在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(),因此可以立即调用callable,但事实并非如此。它只挂在FutureTask.acquireSharedInterruptibly()上,永远不会返回。
也许我在这里过头了。它的工作原理我现在可以使用callable进行设置,但我宁愿没有方法签名声明抛出异常。
有什么建议吗?我是否应该忘记使用可调用函数执行异步调用的这种通用方法?
答案 0 :(得分:0)
这里有两层例外。
一个: 导致调用Callable的异常
if (string.equals("X")){ callable.call();}
2: 调用callable.call()方法时引起的异常(你的&#34;抛出新的MyException(&#34; foobar&#34;);&#34;)
因为在&#34; callable.call();&#34;之前没有任何其他代码,所以删除已检查的异常是安全的。
更改
public <T> Future<T> runAsync(Callable<T> callable) throws Exception
到
public <T> Future<T> runAsync(Callable<T> callable)
另外,你可以这样编码
final Future<String> future = myCaller.runAsync(callable);
try
{
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);
}