2013-07-25 14 views
18

Ho un'attività a lungo termine definita in un servizio Spring. È avviato da un controller MVC Spring. Voglio avviare il servizio e restituire un HttpResponse al chiamante prima che il servizio termini. Il servizio salva un file sul file system alla fine. In javascript ho creato un lavoro di polling per verificare lo stato del servizio.Differenza tra springmvc @Async, DeferredResult, Callable

Nella primavera 3.2 ho trovato l'annotazione @Async, ma non capisco come sia diversa da DeferredResult e Callable. Quando devo usare @Async e quando devo usare DeferredResult?

risposta

3

DeferredResult sfrutta il servlet 3.0 AsyncContext. Non bloccherà il thread come gli altri quando avrai bisogno di un risultato restituito.

Un altro grande vantaggio è che DeferredResult supporta i callback.

21

Async annota un metodo in modo che venga chiamato in modo asincrono.

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

Così primavera potrebbe farlo è necessario definire come sta per essere giustiziato. Per esempio:

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

In questo modo quando si chiama service.DoSomeWork ("parametri") la chiamata viene messa in coda di esecutore di essere chiamato in modo asincrono. Questo è utile per le attività che potrebbero essere eseguite contemporaneamente.

È possibile utilizzare Async per eseguire qualsiasi tipo di attività asincrona. Se ciò che si desidera è chiamare periodicamente un'attività, è possibile utilizzare @ Schedulato (e utilizzare task: scheduler anziché task: executor). Sono modi semplificati di chiamare java Runnables.

DeferredResult <> viene utilizzato per rispondere a una petizione senza bloccare il thread HTTP Tomcat utilizzato per rispondere. Di solito sta per essere il valore di ritorno per un metodo annotato 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; 
    } 
} 

L'esempio precedente manca una cosa importante ed è che non mostra come il risultato differito sta per essere impostato. In qualche altro metodo (probabilmente il metodo setValue) ci sarà un risultato.setResult (valore). Dopo la chiamata a setResult Spring chiamerà la procedura onCompletion e restituirà la risposta alla richiesta HTTP (vedere https://en.wikipedia.org/wiki/Push_technology#Long_polling).

Ma se si esegue il setValue in modo sincrono non c'è alcun vantaggio nell'utilizzo di un risultato posticipato. Qui è dove Async viene in mano. È possibile utilizzare un metodo asincrono per impostare il valore restituito in un determinato punto in futuro utilizzando un altro thread.

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

Async non è necessario per utilizzare un risultato posticipato, è solo un modo per farlo.

Nell'esempio è presente una coda di risultati posticipati che, ad esempio, un'attività pianificata potrebbe eseguire il monitoraggio per elaborare le richieste in sospeso. Inoltre, è possibile utilizzare un meccanismo non bloccante (vedere http://en.wikipedia.org/wiki/New_I/O) per impostare il valore restituito.

Per completare l'immagine è possibile cercare informazioni sui java standard futures (http://docs.oracle.com/javase/1.5.0/docs/api/java/util/concurrent/Future.html) e callables (http://docs.oracle.com/javase/1.5.0/docs/api/java/util/concurrent/Callable.html) che sono in qualche modo equivalenti a Spring DeferredResult e Async.

+0

Puoi spiegare 'service.setValue (risultato); // Imposta il valore! ', Che cosa significa' servizio'? – coderz

+0

Guarda il blocco di codice dopo quello. C'è un esempio di come si dovrebbe implementare il metodo setValue. –

+0

Perché hai bisogno dell'elenco "sospesoRisultati"? Spring non tiene traccia degli oggetti differiti? Se stai impostando il risultato su un risultato Deferred specifico in SetValue, non vedo perché la necessità di questo elenco di oggetti differiti –

Problemi correlati