如何在基于servlet的Web应用程序中运行后台任务?

pri*_*sag 93 multithreading servlets background-process java-ee scheduledexecutorservice

我正在使用Java,我想在我的应用程序中保持servlet不断运行,但我不知道怎么做.我的servlet有一个方法,它每天从数据库中提供用户的计数以及整个数据库中用户的总数.所以我想保持servlet不断运行.

Bal*_*usC 207

你的问题是你误解了servlet的用途.它的目的是对HTTP请求采取行动,仅此而已.您只需要一个每天运行一次的后台任务.

EJB可用吗?使用@Schedule

如果您的环境恰好支持EJB(例如WildFly,JBoss AS/EAP,TomEE,GlassFish等),那么请@Schedule改用.

@Singleton
public class BackgroundJobManager {

    @Schedule(hour="0", minute="0", second="0", persistent=false)
    public void someDailyJob() {
        // Do your job here which should run every start of day.
    }

    @Schedule(hour="*/1", minute="0", second="0", persistent=false)
    public void someHourlyJob() {
        // Do your job here which should run every hour of day.
    }

    @Schedule(hour="*", minute="*/15", second="0", persistent=false)
    public void someQuarterlyJob() {
        // Do your job here which should run every 15 minute of hour.
    }

    @Schedule(hour="*", minute="*", second="*/5", persistent=false)
    public void someFiveSecondelyJob() {
        // Do your job here which should run every 5 seconds.
    }

} 
Run Code Online (Sandbox Code Playgroud)

是的,这就是全部.容器将自动拾取和管理它.

EJB不可用?使用ScheduledExecutorService

如果您的环境不支持EJB(即不是真正的Java EE服务器,例如Tomcat,Jetty等),请使用ScheduledExecutorService.这可以由a启动ServletContextListener.这是一个启动示例:

@WebListener
public class BackgroundJobManager implements ServletContextListener {

    private ScheduledExecutorService scheduler;

    @Override
    public void contextInitialized(ServletContextEvent event) {
        scheduler = Executors.newSingleThreadScheduledExecutor();
        scheduler.scheduleAtFixedRate(new SomeDailyJob(), 0, 1, TimeUnit.DAYS);
        scheduler.scheduleAtFixedRate(new SomeHourlyJob(), 0, 1, TimeUnit.HOURS);
        scheduler.scheduleAtFixedRate(new SomeQuarterlyJob(), 0, 15, TimeUnit.MINUTES);
        scheduler.scheduleAtFixedRate(new SomeFiveSecondelyJob(), 0, 5, TimeUnit.SECONDS);
    }

    @Override
    public void contextDestroyed(ServletContextEvent event) {
        scheduler.shutdownNow();
    }

}
Run Code Online (Sandbox Code Playgroud)

工作类看起来像这样:

public class SomeDailyJob implements Runnable {

    @Override
    public void run() {
        // Do your daily job here.
    }

}
Run Code Online (Sandbox Code Playgroud)
public class SomeHourlyJob implements Runnable {

    @Override
    public void run() {
        // Do your hourly job here.
    }

}
Run Code Online (Sandbox Code Playgroud)
public class SomeQuarterlyJob implements Runnable {

    @Override
    public void run() {
        // Do your quarterly job here.
    }

}
Run Code Online (Sandbox Code Playgroud)

不要考虑在Java EE中使用java.util.Timer/java.lang.Thread

永远不要直接使用java.util.Timer和/或java.lang.Thread在Java EE中使用.这是麻烦的秘诀.在这个与JSF相关的答案中可以找到关于同一问题的详细解释:使用计时器在JSF托管bean中为计划任务生成线程.

  • `ScheduledExecutorService`的一个关键问题:确保**在执行程序中捕获*所有*异常**.如果异常从`run`方法中逃脱,执行程序将默默地停止执行.这是一个不是bug的功能.阅读文档并通过一些谷歌搜索进行研究. (11认同)
  • @BalucS谢谢先生,你的解决方案帮助了我,我了解了ScheduledExecutorService,这对我来说是新手java.再次感谢你. (7认同)