En el post anterior hemos visto como crear un servlet asincrono que realiza una tarea en background . Sin embargo el usuario una vez lanzada la petición y obtenido el mensaje de que el proceso se ejecutara de forma asincrona no recibe ningún aviso de que la tarea ha finalizado .Ya que el fichero html se envio mucho antes de que la tarea en background finalizase.
Para solventar este problema y que el usuario pueda recibir un mensaje de aviso advirtiéndole de que la tarea ha finalizado debemos añadir al servlet que hemos construido previamente un listener .
package com.arquitecturajava; import java.io.IOException; import java.io.PrintWriter; import javax.servlet.AsyncContext; import javax.servlet.AsyncEvent; import javax.servlet.AsyncListener; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @WebServlet(name = "HolaMundo", urlPatterns = { "/HolaMundo" }, asyncSupported = true) public class HolaMundo extends HttpServlet { private static final long serialVersionUID = 1L; protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { final PrintWriter pw = response.getWriter(); pw.println("<html>"); pw.println("<body>"); pw.println("hola mundo asincrono tarea realizandose en background"); System.out .println("Hilo Principal:" + Thread.currentThread().getName()); final AsyncContext contextoAsincrono = request.startAsync(); contextoAsincrono.setTimeout(12000); contextoAsincrono.addListener(new AsyncListener() { @Override public void onTimeout(AsyncEvent arg0) throws IOException { } @Override public void onStartAsync(AsyncEvent arg0) throws IOException { } @Override public void onError(AsyncEvent arg0) throws IOException { } @Override public void onComplete(AsyncEvent arg0) throws IOException { System.out .println(" enviando un correo al usuario (tarea terminada)"); } }); contextoAsincrono.start(new Runnable() { @Override public void run() { for (int i = 0; i <= 10; i++) { System.out.println("Hilo Tarea Asincrona :" + Thread.currentThread().getName()); try { Thread.sleep(1000); } catch (InterruptedException e) { } } contextoAsincrono.complete(); } }); pw.println("</body>"); pw.println("</html>"); pw.close(); } }
Como podemos ver hemos añadido un AsyncListener a nuestro contexto asincrono
contextoAsincrono.addListener(new AsyncListener() {
Realizada esta operación debemos implementar todos los metodos de este interface . Nosotros en concreto nos centraremos en el método onComplete que es el encargado de enviar el correo (pseudocódigo) una vez que nuestra tarea asincrona haya finalizado
public void onComplete(AsyncEvent arg0) throws IOException { System.out.println(" enviando un correo al usuario (tarea terminada)"); <div>
Buen post, que diferencia hay entre usar Servlet Asincronos y usar hilos normales?
Es decir usar una instancia de una clase que extienda de la clase Thread, y que el metodo run sea igual que el mostrado.
Concretamente ¿Porque usar Servlet Asincronos?
Para procesar más peticiones ya que al ser asincrono el thread se libera hasta que llega la respuesta
Tengo un problema, java me dice:
contextoAsincrono.complete();
Identifier expected after this token
Te puede faltar algún “;” en algún sitio?? un signo igual o algo similar 🙂
Veo que las operaciones hechas de forma asíncrona, realizan impresiones de pantalla a través de la consola en el ejemplo. Esto quiere decir que las operaciones asíncronas son para realizar operaciones del lado del servidor y no con la response?
Date cuenta que son operaciones que al ser asincronas no devuelven una respuesta inmediata y por lo tanto si usamos el response podriamos tener problemas de timeout
Gracias.
Muy buen blog, gracias!
Tengo una pregunta:
¿Por qué usar un listener? ¿No añade complejidad y dificulta la legibilidad? Mas al nivel de aplicaciones grandes que al nivel del ejemplo.
Podría enviarse el mail al final del metodo run() del Runnable no?
Gracias y saludos.
Es el mecanismo natural para una petición asincrona ya que esta los necesita
Cuándo se invoca “contextoAsincrono.complete();” el listener se encarga de enviar un mensaje de aviso, pero al mismo tiempo ¿es enviada una “response” al cliente?
Para aclarar la pregunta.
Existen 2 formas de crear el contexto:
public AsyncContext startAsync() , utilizada en este ejemplo.
public AsyncContext startAsync(ServletRequest req, ServletResponse res)
En esta segunda si aparece “res”, con lo cual realizamos operaciones y una vez ejecutado “contextoAsincrono.complete();” se devuelve “res” la cliente.
Con la primera forma, ¿se devuelve “res” al cliente?
Esto ayuda a facilitar la comprension del codigo y a estructurarlo aun más, ya que antes para poder hacer esto se debia ejecutar un hilo que hiciera todo el trabajo.
Gracias por el aporte