1

Я пытаюсь реализовать универсальный класс, который выполняет асинхронно, но я не уверен в семантике.Spring @Async with Future and Callable

@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 через Future.get(), который в конечном итоге снова проверяет, существует ли исключение, и выдает новую оболочку ExecutionException ExecutionException, обнаруженное во внутреннем Run()

Я также попытался сделать следующее в методе:

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

Я понял, что поскольку AsyncExecutionInterceptor вызывает Future.get(), вызываемый вызов будет вызван немедленно, но это было не так. Он просто зависает на FutureTask.acquireSharedInterruptibly() и никогда не возвращается.

Возможно, я нахожусь здесь над моей головой. Он работает так, как я его настраивал с вызываемым сейчас, но я скорее не хочу, чтобы подпись метода объявляла throw Exception.

Любые советы? Должен ли я забыть об этом общем способе делать асинхронные вызовы с вызываемым?

ответ

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); 
     } 
Смежные вопросы