meetup code garden roma e java user group roma: metodi asincroni con spring - vitalij zadneprovskij...

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

Upload: codemotion

Post on 05-Apr-2017

24 views

Category:

Technology


2 download

TRANSCRIPT

Metodi asincroni in SpringVitalij Zadneprovskij

ROME 24-25 MARCH 2017

JUG Roma e Code Garden

I processi del sistema operativo

● Istanza di programma in esecuzione

● Comunicazione limitata

● JVM è un processo, di solito

Thread nel sistema operativo

● Eseguono istruzioni in modo concorrente

● Condividono dati

Fonte immagine: wikipedia.org

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

Ciclo di vita di un thread di Java

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

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();

    }

}

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

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

Esempio didattico di Executor

class ThreadPerTaskExecutor implements Executor {

   public void execute(Runnable r) {

     new Thread(r).start();

   }

 }

Executor in pratica

● Conviene delegare la gestione dei pool di thread al container

● Oppure usare ThreadPoolExecutor e ScheduledThreadPoolExecutor

Interfaccia Callable

public interface Callable<V> {

    V call() throws Exception;

}

● Restituisce un valore del tipo che vogliamo noi

● Può lanciare eccezioni al chiamante

Future

Fonte immagine: boardgamegeek.com

Future

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

waiting il thread chiamante

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;

}

Si può fare di meglio

Le callback● Quando il metodo

asincrono termina, ne chiama un altro

● Metodi distinti in caso di successo o errore

Lana Turner

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

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

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

}

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

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) {}        });

L’inferno delle callback

John Martin “Le Pandemonium” Louvre

Facciamoci aiutare da Java 8

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

● Posso passare questo metodo come argomento:

MiaClasse::mioMetodo

CompletableFuture di Java 8

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

● Gestire errori: exceptionally()

● Ultimo metodo: thenAccept()

Esempio di CompletableFuture

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

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

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

completableFuture.thenAccept(this::lastMethod);

Altro esempio

CompletableFuture.supplyAsync(this::findReceiver)

                     .thenApply(this::sendMsg)

                     .thenAccept(this::notify);

Arriviamo a Spring

Sandro Botticelli, “Primavera”

Configurazione generale

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

<task:annotation­driven />

● Annotation per Spring Boot:

@EnableAsync

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>

Valori di ritorno ammessi

● Future● ListenableFuture● CompletableFuture (richiede Java 8)

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;

    }

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;

    }

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;

    }

Lato Controller

● Nei vari controller, va restituito un DeferredResult o un Callable

● Il DeferredResult deve essere valorizzato nella callback

● Il Callable fa tutto nel metodo call()● Possono contenere il valore da restituire,

oppure un ModelAndView

Silvia Bottini, “Cry”

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);

}