Servlet 3.0 (III) Servlets Asincronos y Listeners

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>
A continuación se muestra una figura aclaratoria :
Una vez implementados todos los pasos invocamos el servlet y en la consola de Tomcat nos aparecera algo como lo siguiente :
Al finalizar la tarea el usuario será avisado por correo de que la tarea ha finalizado correctamente .Por ejemplo este servlet podría encargarse de procesar PDFs pesados y cuando hayan sido construidos enviar un correo al usuario que lo solicito.
It's only fair to share...Share on FacebookShare on Google+Tweet about this on TwitterShare on LinkedIn

About Cecilio Álvarez Caules

Cecilio Álvarez Caules Sun Certified Enterprise Architech (J2EE/JEE).

,

12 Responses to Servlet 3.0 (III) Servlets Asincronos y Listeners

  1. Carlos 28 Diciembre, 2012 at 13:44 #

    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

  2. José Luis Villaverde 3 Marzo, 2013 at 11:45 #

    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?

    • José Luis Villaverde 3 Marzo, 2013 at 12:08 #

      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?

  3. Guillermo Manjon 1 Julio, 2013 at 8:44 #

    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.

    • Cecilio Álvarez Caules 20 Julio, 2013 at 9:12 #

      Es el mecanismo natural para una petición asincrona ya que esta los necesita

  4. nelson 21 Diciembre, 2013 at 10:05 #

    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?

    • Cecilio Álvarez Caules 21 Diciembre, 2013 at 21:51 #

      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

      • nelson 31 Diciembre, 2013 at 4:18 #

        Gracias.

  5. Daniel 27 Diciembre, 2013 at 10:58 #

    Tengo un problema, java me dice:

    contextoAsincrono.complete();
    Identifier expected after this token

    • Cecilio Álvarez Caules 27 Diciembre, 2013 at 15:13 #

      Te puede faltar algún “;” en algún sitio?? un signo igual o algo similar 🙂

  6. Javier Estacuy 6 Agosto, 2014 at 23:35 #

    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?

    • Cecilio Álvarez Caules 8 Agosto, 2014 at 17:52 #

      Para procesar más peticiones ya que al ser asincrono el thread se libera hasta que llega la respuesta

Deja un comentario