Metodi asincroni in spring

39
Metodi asincroni in Spring Vitalij Zadneprovskij ROME 24-25 MARCH 2017

Transcript of Metodi asincroni in spring

Page 1: Metodi asincroni in spring

Metodi asincroni in SpringVitalij Zadneprovskij

ROME 24-25 MARCH 2017

Page 2: Metodi asincroni in spring

JUG Roma e Code Garden

Page 3: Metodi asincroni in spring
Page 4: Metodi asincroni in spring
Page 5: Metodi asincroni in spring

I processi del sistema operativo

● Istanza di programma in esecuzione

● Comunicazione limitata

● JVM è un processo, di solito

Page 6: Metodi asincroni in spring

Thread nel sistema operativo

● Eseguono istruzioni in modo concorrente

● Condividono dati

Fonte immagine: wikipedia.org

Page 7: Metodi asincroni in spring

Thread in Java

● Un main thread può lanciarne altri

● Istanza classe Thread

● Ogni thread ha una sua pila di chiamate

Fonte immagine: http://blog.takipi.com

Page 8: Metodi asincroni in spring

Ciclo di vita di un thread di Java

Fonte immagine: https://www.tutorialspoint.com

Page 9: Metodi asincroni in spring

Lancio di un threadpublic class HelloRunnable implements Runnable {

    public void run() {

        System.out.println("Hello from a thread!");

    }

    public static void main(String args[]) {

        (new Thread(new HelloRunnable())).start();

    }

}

Page 10: Metodi asincroni in spring
Page 11: Metodi asincroni in spring

Thread pool

● Allocare e liberare memoria degrada le prestazioni

● È meglio fare riuso di thread● Un thread usato torna nel pool● Numero di thread nel pool può essere

fisso o variabile

Page 12: Metodi asincroni in spring

Interfaccia Executor

● Astrazione per la gestione dei thread pool● Unico metodo:

void execute(Runnable command);

Che ha un funzionamento simile a:

(new Thread(runnable)).start();

● Astrazione sulla gestione del thread pool

Page 13: Metodi asincroni in spring

Esempio didattico di Executor

class ThreadPerTaskExecutor implements Executor {

   public void execute(Runnable r) {

     new Thread(r).start();

   }

 }

Page 14: Metodi asincroni in spring

Executor in pratica

● Conviene delegare la gestione dei pool di thread al container

● Oppure usare ThreadPoolExecutor e ScheduledThreadPoolExecutor

Page 15: Metodi asincroni in spring

Interfaccia Callable

public interface Callable<V> {

    V call() throws Exception;

}

● Restituisce un valore del tipo che vogliamo noi

● Può lanciare eccezioni al chiamante

Page 16: Metodi asincroni in spring

Future

Fonte immagine: boardgamegeek.com

Page 17: Metodi asincroni in spring

Future

● Rappresenta una computazione● Può essere in corso, eseguita o annullata● Chiamando il metodo get() metto in

waiting il thread chiamante

Page 18: Metodi asincroni in spring

Interfaccia Futurepublic interface Future<V> {

    boolean cancel(boolean mayInterruptIfRunning);

    boolean isCancelled();

    boolean isDone();

    V get() throws InterruptedException, ExecutionException;

    V get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException;

}

Page 19: Metodi asincroni in spring

Si può fare di meglio

Page 20: Metodi asincroni in spring

Le callback● Quando il metodo

asincrono termina, ne chiama un altro

● Metodi distinti in caso di successo o errore

Lana Turner

Page 21: Metodi asincroni in spring

ListenableFuture di Spring Corepublic interface ListenableFuture<T> extends Future<T> {

    void addCallback(ListenableFutureCallback<? super T> var1);

    void addCallback(SuccessCallback<? super T> var1, FailureCallback var2);

}

Page 22: Metodi asincroni in spring

E se la callback dovesse chiamare un’altra callback?

● Può capitare di dover fare varie chiamate consecutive

● Se non si sta attenti, si finisce per scrivere codice difficile da modificare

Page 23: Metodi asincroni in spring

Esempio in JavaListenableFuture<String> listenable = asyncService.listenableMethod();        listenable.addCallback(new ListenableFutureCallback<String>(){            public void onSuccess(String s) {                try {                    ListenableFuture lf = asyncService.listenableMethod();                    lf.addCallback(new ListenableFutureCallback() {                        public void onFailure(Throwable throwable) {                            try {                                ListenableFuture lf2 = asyncService.listenableMethod();                            } catch (InterruptedException e) { logger.error(e.getLocalizedMessage(), e); }                        }                        public void onSuccess(Object o) { }                    });                } catch (InterruptedException e) { logger.error(e.getLocalizedMessage(), e); }            }            public void onFailure(Throwable throwable) {}        });

Page 24: Metodi asincroni in spring

L’inferno delle callback

John Martin “Le Pandemonium” Louvre

Page 25: Metodi asincroni in spring

Facciamoci aiutare da Java 8

● Ho una classe MiaClasse che ha un metodo mioMetodo()

● Posso passare questo metodo come argomento:

MiaClasse::mioMetodo

Page 26: Metodi asincroni in spring

CompletableFuture di Java 8

● Passiamo i metodi come argomenti● Aggiungere callback: thenApply()

● Gestire errori: exceptionally()

● Ultimo metodo: thenAccept()

Page 27: Metodi asincroni in spring

Esempio di CompletableFuture

CompletableFuture<String> completableFuture = asyncService.completableMethod();

completableFuture = completableFuture.exceptionally(this::onException);

completableFuture = completableFuture.thenApply(this::intermediateMethod);

completableFuture.thenAccept(this::lastMethod);

Page 28: Metodi asincroni in spring

Altro esempio

CompletableFuture.supplyAsync(this::findReceiver)

                     .thenApply(this::sendMsg)

                     .thenAccept(this::notify);

Page 29: Metodi asincroni in spring

Arriviamo a Spring

Sandro Botticelli, “Primavera”

Page 30: Metodi asincroni in spring

Configurazione generale

● Da XML, dopo aver aggiunto il namespace XML “task”:

<task:annotation­driven />

● Annotation per Spring Boot:

@EnableAsync

Page 31: Metodi asincroni in spring

Configurazione TaskExecutor

● Di default viene usato il SimpleAsyncTaskExecutor che non riusa i thread

● Per usare il ThreadPoolTaskExecutor:

<bean id="taskExecutor" class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor">

        <property name="corePoolSize" value="5" />

        <property name="maxPoolSize" value="10" />

        <property name="queueCapacity" value="25" />

    </bean>

Page 32: Metodi asincroni in spring

Valori di ritorno ammessi

● Future● ListenableFuture● CompletableFuture (richiede Java 8)

Page 33: Metodi asincroni in spring

Esempio di Future    @Async

    public Future<String> futureMethod(){

        Future<String> future = null;

        try {

            Thread.sleep(1000L);

            future = AsyncResult.forValue("OK");

        } catch (InterruptedException e) {

            logger.error(e.getLocalizedMessage(), e);

            future = AsyncResult.forExecutionException(e);

        }

        return future;

    }

Page 34: Metodi asincroni in spring

Esempio di ListenableFuture    @Async

    public ListenableFuture listenableMethod() throws InterruptedException {

        ListenableFuture<String> listenableFuture = null;

        try {

            Thread.sleep(1000L);

            listenableFuture = AsyncResult.forValue("OK");

        } catch (InterruptedException e) {

            logger.error(e.getLocalizedMessage(), e);

            listenableFuture = AsyncResult.forExecutionException(e);

        }

        return listenableFuture;

    }

Page 35: Metodi asincroni in spring

Esempio di CompletableFuture    @Async

    public CompletableFuture<String> completableMethod() throws InterruptedException{

        CompletableFuture<String> completableFuture = new CompletableFuture<String>();

        try {

            Thread.sleep(1000L);

            completableFuture.complete("OK");

        } catch (InterruptedException e) {

            logger.error(e.getLocalizedMessage(), e);

            completableFuture.completeExceptionally(e);

        }

        return completableFuture;

    }

Page 36: Metodi asincroni in spring

Lato Controller

● Nei vari controller, va restituito un DeferredResult

● Il DeferredResult deve essere valorizzato nella callback

● Può contenere il valore da restituire, oppure un ModelAndView

Page 37: Metodi asincroni in spring

Silvia Bottini, “Cry”

Page 38: Metodi asincroni in spring

Esempio Spring Data JPAinterface EmployeeRepository extends JpaRepository<Employee, Long> {

    @Async

    Future<List<Employee>> findDistinctByFirstName(String firstName);

    @Async

    CompletableFuture<Employee> findFirstByFirstNameIgnoreCase(String firstName);

    @Async

    ListenableFuture<Employee> findFirstByLastName(String lastName);

}

Page 39: Metodi asincroni in spring