在Tomcat中运行后台Java程序

在Tomcat中运行后台Java程序,java,tomcat,batch-processing,Java,Tomcat,Batch Processing,这里有人能提供建议吗?我遇到的情况是,用户将通过JavaJSP和servlet交互地向我的应用程序提交数据挖掘请求,该应用程序将动态地计算数据关联规则等等 由于这样的工作可能需要一段时间,我正在考虑在服务器上进行某种处理,以便在后台运行这样的请求,这样它就不会“锁定”会话,并且可能会使用大量的服务器内存来损害系统 由于该系统由一系列Java JSP和Servlet组成,运行在MySQL数据库上的Tomcat容器中,有人能给我们建议一条前进的道路吗 谢谢 摩根先生我认为你应该能够在这里完成你想做的

这里有人能提供建议吗?我遇到的情况是,用户将通过JavaJSP和servlet交互地向我的应用程序提交数据挖掘请求,该应用程序将动态地计算数据关联规则等等

由于这样的工作可能需要一段时间,我正在考虑在服务器上进行某种处理,以便在后台运行这样的请求,这样它就不会“锁定”会话,并且可能会使用大量的服务器内存来损害系统

由于该系统由一系列Java JSP和Servlet组成,运行在MySQL数据库上的Tomcat容器中,有人能给我们建议一条前进的道路吗

谢谢


摩根先生

我认为你应该能够在这里完成你想做的事情。下面是一些例子。使用此选项,您可以启动一个cron,该cron可以快速轮询以处理传入的请求。实际上,我是在我的一个项目中这样做的。

一个轻量级解决方案(与使用quartz之类的调度器不同)是将处理放在后台线程中,并通过ExecutorService运行



也许您真正想要的是JMS,但是在Tomcat上使用它需要额外的努力,因为它只是一个Servlet容器。您可以更直接地切换到真实的AppServer,如Glassfish或JBoss,或者自己向Tomcat添加JMS功能(链接下方)

使用一个

不过,您应该做一些事情,将线程标记为守护进程线程,这样它至少不会在错误场景中束缚tomcat,并且当servlet上下文被破坏时(例如,当您重新部署或停止应用程序时),您应该停止执行者。为此,请使用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;
    }
}

如果您使用的是Spring,所有这些可能都可以实现,即使您希望返回响应吗?此外,Tomcat使用线程池,在必要时可以扩展以服务多个同时请求。您是否需要向用户显示“数据挖掘请求”的结果(或者至少通知他们已完成的作业)?您需要如何做到这一点?我在想,当一项工作完成后,可以通过电子邮件向用户发送结果。我在系统中的其他地方使用Quartz进行每小时的计划工作,但这是可能的。Quartz是一个很好的选择。它将执行“立即运行一次工作”很好。另一个优点是,它将为您提供重新启动功能。当您启动作业时,quartz可以“保存”请求,并在系统停机时重新启动作业。您可以“免费”获得所有这些,既然你已经有了它,你就已经知道如何使用它了。如果你不需要的话,为什么还要在堆栈中添加新的工具包呢?一个非守护进程线程如何在错误场景中绑定tomcat?我一直在走这条路,但我担心的是,当tomcat关闭时,能否可靠而优雅地关闭我的ExeExeService。我不能失去什么正在执行。显然您不能依赖ServletContextListener。请参阅和@nos,那么myJob Runnable应该有一个类似于
的run方法,而(true){Thread.sleep(1000);//多做点事。}
。不是吗?]@Débora我不知道您想在运行中做什么()方法。不过,在与执行器一起使用的作业中,您几乎不会有无限循环。@不,谢谢您的回复。我的意思是,假设程序(如应用程序统计检查…?)应该连续/并行于tomcat运行,那么我们不必无限地运行deamon线程吗?
  <listener>
    <listener-class>com.example.ExecutorContextListener</listener-class>
  </listener>
ExecutorService executor = (ExecutorService )getServletContext().getAttribute("MY_EXECUTOR");
...
executor.submit(myJob);