Разница между springmvc @Async, DeferredResult, Callable

У меня длинная задача, определенная в службе spring, она запускается контроллером springmvc. Я хочу начать сервис и вернуть HttpResponse для вызывающего абонента до окончания обслуживания. Служба сохраняет файл в файловой системе в конце. В javascript я создал задание на опрос, чтобы проверить статус службы.

В spring 3.2 я нашел @Aync-аннотацию, но я не понимаю, как она отличается от DeferredResult и Callable. Когда мне нужно использовать @Async? и когда я использую DeferredResult?

Ответы

Ответ 1

Async аннотирует метод, поэтому он будет вызываться асинхронно.

@org.springframework.stereotype.Service
public class MyService {
    @org.springframework.scheduling.annotation.Async
    void DoSomeWork(String url) {
        [...]
    }
}

Итак, Spring может сделать это, вам нужно определить, как это будет выполняться. Например:

<task:annotation-driven />
<task:executor id="executor" pool-size="5-10" queue-capacity="100"/>

Таким образом, когда вы вызываете service.DoSomeWork( "параметр" ), вызов помещается в очередь исполнителя, который вызывается асинхронно. Это полезно для задач, которые могут выполняться одновременно.

Вы можете использовать Async для выполнения любой асинхронной задачи. Если вы хотите периодически вызывать задачу, вы можете использовать @Scheduled (и использовать задачу: планировщик вместо задачи: executor). Это упрощенные способы вызова java Runnables.

DeferredResult < > используется для ответа на петицию, не блокируя поток HTTP Tomcat, используемый для ответа. Обычно это будет возвращаемое значение для аннотированного метода ResponseBody.

@org.springframework.stereotype.Controller
{
    private final java.util.concurrent.LinkedBlockingQueue<DeferredResult<String>> suspendedRequests = new java.util.concurrent.LinkedBlockingQueue<>();

    @RequestMapping(value = "/getValue")
    @ResponseBody
    DeferredResult<String> getValue() {
            final DeferredResult<String> result = new DeferredResult<>(null, null);
            this.suspendedRequests.add(result);
            result.onCompletion(new Runnable() {
            @Override
            public void run() {
        suspendedRequests.remove(result);
            }
});
            service.setValue(result); // Sets the value!
            return result;
    }
}

В предыдущем примере отсутствует одна важная вещь, и это не показывает, как будет установлен отложенный результат. В каком-то другом методе (вероятно, метод setValue) будет создан result.setResult(значение). После вызова setResult Spring будет вызывать процедуру onCompletion и вернуть ответ на HTTP-запрос (см. https://en.wikipedia.org/wiki/Push_technology#Long_polling).

Но если вы просто выполняете setValue синхронно, нет никакого преимущества в использовании отложенного результата. Здесь есть Async. Вы можете использовать метод async для установки возвращаемого значения в какой-то момент в будущем с помощью другого потока.

    @org.springframework.scheduling.annotation.Async
    void SetValue(DeferredResult<String> result) {
        String value;
        // Do some time consuming actions
        [...]
        result.setResult(value);
    }

Async не нужен для использования отложенного результата, его только один способ сделать это.

В примере есть очередь отложенных результатов, которые, например, можно было планировать задание для обработки ожидающих запросов. Также вы можете использовать некоторый механизм блокировки (см. http://en.wikipedia.org/wiki/New_I/O), чтобы установить возвращаемое значение.

Чтобы завершить изображение, вы можете найти информацию о стандартных фьючерсах java (http://docs.oracle.com/javase/1.5.0/docs/api/java/util/concurrent/Future.html) и callables (http://docs.oracle.com/javase/1.5.0/docs/api/java/util/concurrent/Callable.html), которые в некоторой степени эквивалентны Spring DeferredResult и Async.

Ответ 2

DeferredResult использует преимущества сервлета 3.0 AsyncContext. Он не будет блокировать поток, как другие, когда вам нужно вернуть результат.

Еще одно большое преимущество заключается в том, что DeferredResult поддерживает обратные вызовы.