2013-03-06 40 views
1

我想實現異步執行的可調用一個泛型類,但我不知道的語義。春@Async與未來可贖回

@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註釋異步執行任意可調用的任意操作。

我不確定在拋出方法簽名的條款除外。

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的子句中聲明的異常?

我已經宣佈的唯一原因是因爲這樣我打電話的調用。我原本在異步方法如下:

FutureTask<T> futureTask = new FutureTask<T>(callable); 
futureTask.run(); 
return futureTask; 

但是,當異常是從可調用該實例中拋出的,它就會在爲ExecutionException裹兩次,當FutureTask.run()最終被稱爲第一次FutureTask.Sync.innerRun()捕獲異常,並調用innnerSetException(),當AsyncExecutionIntercepter通過的Future.get(),最終再次檢查是否有異常,並拋出一個新的ExecutionException當包裹從未來得到結果第二次ExecutionException在innerRun中捕獲()

我也嘗試在該方法中執行以下操作:

FutureTask<T> futureTask = new FutureTask<T>(callable); 
return futureTask; 

我曾想過,自AsyncExecutionInterceptor調用Future.get()之後,可立即調用可調用對象,但事實並非如此。它只是掛在FutureTask.acquireSharedInterruptibly()上,並且永遠不會返回。

也許我在我頭上這裏。它的工作原理是如何使用可調用的設置,但我寧願沒有方法簽名聲明拋出異常。

有什麼建議嗎?我應該忘記這種使用可調用的異步調用的通用方法嗎?

回答

0

這裏有2層例外。

之一: 導致的可贖回

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

兩個呼叫除外: 調用callable.call()方法時,導致異常(您的 「拋出新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); 
     }