40 votes

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

Quelqu'un peut-il nous conseiller ? Je suis dans une situation où les utilisateurs soumettent des requêtes d'exploration de données de manière interactive via un JSP Java et un servlet à une de mes applications qui élabore dynamiquement des règles d'association sur les données et plus encore.

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

Le système étant constitué d'une série de JSP et de servlets Java fonctionnant dans un conteneur Tomcat sur une base de données MySQL, quelqu'un peut-il nous conseiller sur la marche à suivre ?

Remerciements

M. Morgan

48voto

nos Points 102226

Utiliser un ExecutorService .

Il y a quelques choses que vous devriez faire cependant, marquer le thread comme un thread démon pour qu'il ne bloque pas tomcat dans les scénarios d'erreur, et vous devriez arrêter l'exécuteur quand votre contexte de servlet est détruit (par exemple quand 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 nécessaires à l'exécution des tâches d'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 tâches :

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

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

5voto

limc Points 14557

Je pense que l'ordonnanceur Quartz devrait être en mesure d'accomplir ce que vous voulez faire ici. Voici quelques exemples de exemples de Quartz . En utilisant cela, vous pouvez démarrer un cron qui pollue rapidement pour traiter la ou les requêtes entrantes. C'est ce que j'ai fait pour l'un de mes projets.

3voto

a_horse_with_no_name Points 100769

Une solution légère (par opposition à l'utilisation d'un planificateur comme quartz) consisterait à placer le traitement dans un thread d'arrière-plan et à l'exécuter par l'intermédiaire d'un 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

0voto

Marcin Michalski Points 934

Peut-être que JMS est ce que vous recherchez vraiment, mais cela demande un effort supplémentaire pour l'utiliser sur Tomcat parce qu'il n'est qu'un conteneur de servlet. Vous pouvez passer à un vrai AppServer comme Glassfish ou JBoss ou ajouter la fonctionnalité JMS à Tomcat par vos propres moyens (lien ci-dessous).

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

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X