Nir*_*hra 5 java tomcat servlets background-process java-ee
我在Apache Tomcat上使用JSP/Servlet.我必须每10分钟运行一次方法.我怎样才能做到这一点?
Bal*_*usC 10
当您使用的是Tomcat(它只是一个准系统servlet容器)时,您不能使用EJB @Schedule,这是Java EE规范推荐的.你最好的选择是ScheduledExecutorService来自Java 1.5的java.util.concurrent包.您可以通过以下方式触发此操作ServletContextListener:
@WebListener
public class BackgroundJobManager implements ServletContextListener {
    private ScheduledExecutorService scheduler;
    @Override
    public void contextInitialized(ServletContextEvent event) {
        scheduler = Executors.newSingleThreadScheduledExecutor();
        scheduler.scheduleAtFixedRate(new SomeTask(), 0, 10, TimeUnit.MINUTES);
    }
    @Override
    public void contextDestroyed(ServletContextEvent event) {
        scheduler.shutdownNow();
    }
}
这个SomeTask类看起来像这样:
public class SomeTask implements Runnable {
    @Override
    public void run() {
        // Do your job here.
    }
}
如果您实际上使用的是具有EJB支持的真正Java EE容器以及所有on em(如Glassfish,JBoss AS,TomEE等),那么您可以将@SingletonEJB与@Schedule方法一起使用.这样容器就会担心汇集和销毁线程.您只需要以下EJB:
@Singleton
public class SomeTask {
    @Schedule(hour="*", minute="*/10", second="0", persistent=false)
    public void run() {
        // Do your job here.
    }
} 
请注意,通过这种方式,您可以通过常规方式(@PersistenceContext等等)继续透明地使用容器管理事务,这是不可能的ScheduledExecutorService- 您必须手动获取实体管理器并手动启动/提交/结束事务,但您会默认情况下,已经没有像Tomcat这样的准系统servlet容器上有另一个选项.
请注意,您永远不Timer应该在运行Java EE Web应用程序的"长寿"中使用a .它有以下主要问题,使其不适合在Java EE中使用(引自Java Concurrency in Practice):
Timer对系统时钟的变化很敏感,ScheduledExecutorService不是.Timer只有一个执行线程,因此长时间运行的任务可以延迟其他任务.ScheduledExecutorService可以配置任意数量的线程.TimerTask一个线程中抛出的任何运行时异常,因此使得Timer死亡,即计划任务将不再运行(直到您重新启动服务器).ScheduledThreadExecutor不仅可以捕获运行时异常,还可以根据需要处理它们.抛出异常的任务将被取消,但其他任务将继续运行.阅读ScheduledExecutorService它必须由ServletContextListener启动
public class MyContext implements ServletContextListener 
{
    private ScheduledExecutorService sched;
    @Override
    public void contextInitialized(ServletContextEvent event) 
    {
        sched = Executors.newSingleThreadScheduledExecutor();
        sched.scheduleAtFixedRate(new MyTask(), 0, 10, TimeUnit.MINUTES);
    }
    @Override
    public void contextDestroyed(ServletContextEvent event) 
    {
        sched.shutdownNow();
    }
}
另外,您可以尝试使用ServletContextListener中的Java Timer,但不建议在 Java EE 容器中使用,因为它会夺走容器对线程资源的控制。(ScheduledExecutorService 的第一个选项是可行的方法)。
Timer timer = new Timer("MyTimer");
MyTask t = new MyTask();
//Second Parameter is the specified the Starting Time for your timer in
//MilliSeconds or Date
//Third Parameter is the specified the Period between consecutive
//calling for the method.
timer.schedule(t, 0, 1000*60*10);
该MyTask实现TimerTask是一个实现该接口的类Runnable,因此您必须使用代码重写 run 方法:
class MyTask extends TimerTask 
{
  public void run() 
  { 
    // your code here
  }
}