2011-02-05 13 views
39

¿Alguien puede asesorar aquí? Tengo una situación en la que los usuarios enviarán solicitudes de minería de datos de forma interactiva a través de Java JSP y servlet a una aplicación mía que resolverá dinámicamente las reglas de asociación en datos y más.Ejecutando un programa Java de fondo en Tomcat

Como tal trabajo puede tomar un tiempo, estoy pensando en algún tipo de proceso en el servidor para ejecutar una solicitud en segundo plano, por lo que no 'bloquear' la sesión y posiblemente utilizar grandes cantidades de servidor memoria en detrimento del sistema.

Como el sistema se compone de una serie de Java JSP y servlets que se ejecutan en un contenedor Tomcat sobre una base de datos MySQL, ¿alguien puede aconsejar un camino a seguir?

Gracias

Sr. Morgan

+0

¿Espera para dar una respuesta de vuelta? Además, Tomcat utiliza grupos de subprocesos que pueden expandirse cuando sea necesario para atender múltiples solicitudes simultáneas. –

+0

¿Necesita volver a mostrar a los usuarios los resultados de las "solicitudes de minería de datos" (o al menos notificarlos sobre los trabajos completados)? ¿Y cómo necesitas hacer eso? –

+0

Estaba pensando que cuando se termina un trabajo, el usuario puede ser enviado por correo electrónico para decir que los resultados están disponibles. –

Respuesta

5

creo cuarzo programador debe ser capaz de lograr lo que quiere hacer aquí. Estos son algunos de los examples from Quartz. Al usar esto, puede iniciar un cron que sondee rápidamente para procesar las solicitudes entrantes. De hecho, hice eso para uno de mis proyectos.

+0

Uso Quartz en otro lugar del sistema para trabajos programados por hora, pero es una posibilidad. –

+3

Quartz es una buena opción. Hará "Ejecutar trabajo una vez, ahora" bastante bien.La otra ventaja es que le dará la capacidad de reinicio. Cuando comienzas el trabajo, el cuarzo puede "guardar" la solicitud y volver a iniciar el trabajo si el sistema se cae. Obtienes todo eso "gratis", y como ya lo tienes, ya sabes cómo usarlo. ¿Por qué agregar un nuevo kit a tu stack si no tienes que hacerlo? –

+0

@Will: +1 ... bien dicho. :) – limc

0

Tal JMS es lo que realmente buscan sin embargo, requiere un esfuerzo extra para usar que en Tomcat porque es sólo contenedor servlet. Es posible que eigher interruptor para AppServer real como Glassfish o JBoss o añadir funcionalidad a JMS Tomcat por su propia cuenta (enlace más abajo)

http://blogs.captechconsulting.com/blog/jairo-vazquez/tomcat-and-jms

48

Utilice un ExecutorService.

Sin embargo, hay algunas cosas que debes hacer, marcar el hilo como un daemon para que atleast no atorgue a tomcat en situaciones de error, y debes detener el ejecutor cuando se destruya tu contexto de servlet (por ejemplo, cuando vuelves a implementar o detener su aplicación para ello, utilice un ServletContextListener:.

public class ExecutorContextListener implements ServletContextListener { 
    private ExecutorService executor; 

    public void contextInitialized(ServletContextEvent arg0) { 
     ServletContext context = arg0.getServletContext(); 
     int nr_executors = 1; 
     ThreadFactory daemonFactory = new DaemonThreadFactory(); 
     try { 
      nr_executors = Integer.parseInt(context.getInitParameter("nr-executors")); 
     } catch (NumberFormatException ignore) {} 

     if(nr_executors <= 1) { 
     executor = Executors.newSingleThreadExecutor(daemonFactory); 
     } else { 
     executor = Executors.newFixedThreadPool(nr_executors,daemonFactory); 
     } 
      context.setAttribute("MY_EXECUTOR", executor); 
     } 

    public void contextDestroyed(ServletContextEvent arg0) { 
     ServletContext context = arg0.getServletContext(); 
     executor.shutdownNow(); // or process/wait until all pending jobs are done 
    } 

} 
import java.util.concurrent.Executors; 
import java.util.concurrent.ThreadFactory; 

/** 
* Hands out threads from the wrapped threadfactory with setDeamon(true), so the 
* threads won't keep the JVM alive when it should otherwise exit. 
*/ 
public class DaemonThreadFactory implements ThreadFactory { 

    private final ThreadFactory factory; 

    /** 
    * Construct a ThreadFactory with setDeamon(true) using 
    * Executors.defaultThreadFactory() 
    */ 
    public DaemonThreadFactory() { 
     this(Executors.defaultThreadFactory()); 
    } 

    /** 
    * Construct a ThreadFactory with setDeamon(true) wrapping the given factory 
    * 
    * @param thread 
    *   factory to wrap 
    */ 
    public DaemonThreadFactory(ThreadFactory factory) { 
     if (factory == null) 
      throw new NullPointerException("factory cannot be null"); 
     this.factory = factory; 
    } 

    public Thread newThread(Runnable r) { 
     final Thread t = factory.newThread(r); 
     t.setDaemon(true); 
     return t; 
    } 
} 

que tendrá que añadir el detector contexto a su web.xml, donde también se puede especificar el número de hilos que querrá correr los trabajos de fondo:

<listener> 
    <listener-class>com.example.ExecutorContextListener</listener-class> 
    </listener> 

Puedes acceder al ejecutor de su servlet y enviar los trabajos a la misma:

ExecutorService executor = (ExecutorService)getServletContext().getAttribute("MY_EXECUTOR"); 
... 
executor.submit(myJob); 

Si está utilizando la primavera, todo esto probablemente se puede hacer aún simpler

+0

¿Cómo ataría un thread no demoníaco a tomcat en un escenario de error? –

+0

Estaba yendo por este camino, pero me preocupa poder apagar mi ExecutorService de manera confiable y confiable cuando se cierre el tomcat. No puedo perder lo que está ejecutando. Aparentemente no puedes confiar en ServletContextListener. Consulte http://stackoverflow.com/questions/1549924/shutdown-hook-for-java-web-application y http://stackoverflow.com/questions/11443133/shutdown-hook-in-tomcat-necessary-not-running –

+0

@nos, entonces myJob Runnable debería tener un método de ejecución como 'while (true) {Thread.sleep (1000); // hago algo más ...} '¿no es así?] –

Cuestiones relacionadas