1

我正在尝试实现一个异步执行可调用对象的通用类,但我不确定语义。

@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() 上并且永远不会返回。

也许我在这里过头了。它现在如何使用可调用文件进行设置,但我宁愿没有方法签名声明抛出异常。

有什么建议吗?我应该忘记这种使用可调用对象进行异步调用的通用方式吗?

4

1 回答 1

0

这里有两层异常。

一:导致调用Callable的异常

if (string.equals("X")){ callable.call();}

二:调用callable.call()方法时引发的异常(你的"throw new MyException("foobar");")

由于您在“callable.call();”之前没有任何其他代码,因此删除检查的异常是安全的。

改变

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);
        }
于 2013-11-24T05:33:58.223 回答