web-dev-qa-db-fra.com

Exécution d'un programme Java en arrière-plan dans Tomcat

Quelqu'un peut-il conseiller ici? Dans certaines situations, les utilisateurs soumettent des demandes d’exploration de données de manière interactive via un JSP Java et un servlet à une application mienne qui élabore de manière dynamique les règles d’association relatives aux données, etc. 

Comme un tel travail peut prendre un certain temps, je songe à une sorte de processus sur le serveur pour exécuter une telle requête en arrière-plan, de sorte qu'il ne "verrouille" pas la session et utilise éventuellement une quantité énorme de mémoire serveur au détriment du système.

Le système étant constitué d'une série de JSP et de servlets Java s'exécutant dans un conteneur Tomcat sur une base de données MySQL, est-ce que quelqu'un peut conseiller une solution?

Merci

Mr Morgan

39
mr morgan

Utilisez un ExecutorService .

Cependant, vous devez faire quelques choses, marquer le fil comme un fil démon pour ne pas nuire à Tomcat dans les scénarios d'erreur, et vous devez arrêter l'exécuteur lorsque le contexte de votre servlet est détruit (par exemple, lorsque vous redéployez ou arrêtez votre application). Pour ce faire, utilisez 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;
    }
}

Vous devrez ajouter l'écouteur de contexte à votre fichier web.xml, où vous pourrez également spécifier le nombre de threads pour lesquels vous souhaitez exécuter les travaux en arrière-plan:

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

Vous pouvez accéder à l'exécuteur à partir de votre servlet et lui soumettre des travaux:

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

Si vous utilisez Spring, tout cela peut probablement être rendu encore plus simple

48
nos

Je pense que le programmateur Quartz devrait pouvoir accomplir ce que vous voulez faire ici. Voici quelques exemples de extraits de Quartz . Grâce à cela, vous pouvez démarrer un cron qui interroge rapidement pour traiter les demandes entrantes. C'est ce que j'ai fait pour l'un de mes projets.

5
limc

Une solution légère (par opposition à l'utilisation d'un planificateur tel que quartz) consisterait à placer le traitement dans un thread en arrière-plan et à l'exécuter via un service d'exécution (ExecutorService). 

http://download.Oracle.com/javase/6/docs/api/Java/util/concurrent/Executors.html
http://download.Oracle.com/javase/6/docs/api/Java/util/concurrent/ExecutorService.html

3

JMS est peut-être ce que vous cherchez vraiment, mais son utilisation sur Tomcat nécessite des efforts supplémentaires, car il ne s'agit que de Servlet Container. Vous pouvez choisir de passer à un véritable AppServer comme Glassfish ou JBoss ou d’ajouter des fonctionnalités JMS à Tomcat par vos propres moyens 

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

0
Marcin Michalski