A partir del éxito del post del otro día “Activando tareas periódicamente con Spring” aprovecho para escribir este de un tema muy parecido. Ejecutar métodos asíncronamente en Spring.
Ejecutar métodos de manera asíncrona nos permite no parar el proceso mientras se ejecuta otra acción. Por ejemplo, en una aplicación web que procesa vídeo, nos permite que cuando el usuario nos sube el vídeo este se procese en segundo plano i así nosotros devolver una respuesta rápida ‘Estamos procesando tu vídeo’.
Spring nos ofrece una manera también muy simple de hacer esto:
Inicializar la aplicación
Al igual que hacíamos con los métodos que se ejecutaban periódicamente debemos activar la funcionalidad al declarar la aplicación(Con la anotación @EnableAsync):
@SpringBootApplication @EnableAsync public class App { public static void main(String[] args) { SpringApplication.run(App.class, args); } }
Crear Servicio con los métodos que se ejecutarán asíncronamente
Después ya podemos declarar nuestros servicios que se ejecutarán de manera asíncrona(Los anotamos con @Async):
@Service public class AsyncTask { @Async public void asyncWork(String s) { for ( int i=0; i<20; i++ ) { System.out.println("loop "+s+" "+i); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } } }
Ejecutar
Ahora, ya podemos utilizarlo en nuestro controlador Web(Por ejemplo):
@Autowired AsyncTask asyncTask; @RequestMapping("/asyncTask") public String asyncTask(Model model) { /* Estos tres métodos se ejecutarán en paralelo asíncronamente */ asyncTask.asyncWork("sub1"); asyncTask.asyncWork("sub2"); asyncTask.asyncWork("sub3"); return "asyncTask"; }
Devolver parámetros
En este ejemplo no lo hacemos, pero si quisiéramos podríamos hacer que estos métodos devolvieran un parámetro. El método debería devolver un Objeto del tipo ‘Future’ que será rellenado cuando el método finalice:
Declaración del método:
@Async public Future<String> asyncWork() { System.out.println( "Ejecutando método" ); try { Thread.sleep(5000); return new AsyncResult<String>("Que pasa neng !!!!"); } catch (Exception e) { e.printStackTrace(); } return null; }
Como leemos el resultado:
Future<String> future = asyncTask.asyncWork(); /* Bucle hasta que termine... */ while (true) { if (future.isDone()) { System.out.println("Por fin terminó - " + future.get()); break; } System.out.println("Esperando un segundito mas... "); Thread.sleep(1000); } System.out.println(“Y recuerda que también es tonto hacer algo asíncrono y después quedarte esperando hasta que termine...”);
Ya veis… Desarrollar aplicaciones modernas que hagan cosas en segundo plano es super fácil con Spring.