it-swarm.com.de

Ausführen eines Java-Hintergrundprogramms in Tomcat

Kann jemand hier raten? Ich habe eine Situation, in der Benutzer Data Mining-Anforderungen interaktiv über eine Java-JSP und ein Servlet an eine Anwendung von mir übermitteln, die Verknüpfungsregeln für Daten und mehr dynamisch ausgearbeitet. 

Da ein solcher Job eine Weile dauern kann, denke ich an eine Art Prozess auf dem Server, um eine solche Anforderung im Hintergrund auszuführen, sodass die Sitzung nicht 'gesperrt' wird und möglicherweise riesige Mengen an Serverspeicher zum Nachteil verwendet werden vom System.

Kann das System aus einer Reihe von Java-JSPs und -Servlets bestehen, die in einem Tomcat-Container über eine MySQL-Datenbank ausgeführt werden.

Vielen Dank

Herr Morgan

39
mr morgan

Verwenden Sie einen ExecutorService .

Es gibt jedoch ein paar Dinge, die Sie tun sollten. Markieren Sie den Thread als Daemon-Thread, sodass Tomcat in Fehlerszenarien nicht gebunden wird. Sie sollten den Executor anhalten, wenn Ihr Servlet-Kontext zerstört wird (z. B. wenn Sie die Anwendung erneut implementieren oder beenden Verwenden Sie dazu einen 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;
    }
}

Sie müssen den Kontextlistener zu Ihrer web.xml hinzufügen, in der Sie auch die Anzahl der Threads angeben können, die Sie für die Ausführung der Hintergrundjobs verwenden möchten:

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

Sie können über Ihr Servlet auf den Executor zugreifen und ihm Jobs übergeben:

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

Wenn Sie Spring verwenden, kann all dies wahrscheinlich noch einfacher gemacht werden einfacher

48
nos

Ich denke, Quarz-Scheduler sollte in der Lage sein, das zu erreichen, was Sie hier tun möchten. Hier sind einige der Beispiele aus Quartz . Auf diese Weise können Sie einen cron starten, der die eingehenden Anfragen schnell abfragt. Ich habe das tatsächlich für eines meiner Projekte gemacht.

5
limc

Eine einfache Lösung (im Gegensatz zur Verwendung eines Schedulers wie Quarz) wäre, die Verarbeitung in einen Hintergrundthread zu setzen und diese über einen ExecutorService auszuführen. 

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

Vielleicht ist JMS genau das, wonach Sie suchen, es erfordert jedoch einen zusätzlichen Aufwand, um es auf Tomcat zu verwenden, da es sich nur um Servlet-Container handelt. Sie können entweder auf echte AppServer wie Glassfish oder JBoss umsteigen oder Tomcat JMS-Funktionalität selbst hinzufügen (unter dem Link). 

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

0