您的问题是您误解了servlet 的用途。它旨在对 HTTP 请求采取行动,仅此而已。您只需要一个每天运行一次的后台任务。
EJB 可用吗?使用@Schedule
如果您的环境恰好支持 EJB(即真正的 Java EE 服务器,例如 WildFly、JBoss、TomEE、Payara、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.
}
}
是的,仅此而已。容器会自动拾取并管理它。
EJB 不可用?使用ScheduledExecutorService
如果您的环境不支持 EJB(即,您使用的不是真正的 Java EE 服务器,而是准系统 servletcontainer,例如 Tomcat、Jetty 等),请使用 ScheduledExecutorService。这可以由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();
}
}
工作类如下所示:
public class SomeDailyJob implements Runnable {
@Override
public void run() {
// Do your daily job here.
}
}
public class SomeHourlyJob implements Runnable {
@Override
public void run() {
// Do your hourly job here.
}
}
public class SomeQuarterlyJob implements Runnable {
@Override
public void run() {
// Do your quarterly job here.
}
}
public class SomeFiveSecondelyJob implements Runnable {
@Override
public void run() {
// Do your quarterly job here.
}
}
永远不要考虑在基于 Java EE / Servlet 的环境中使用 java.util.Timer/java.lang.Thread
最后但同样重要的是,永远不要在 Java EE 中直接使用 java.util.Timer 和/或 java.lang.Thread。这是麻烦的秘诀。可以在这个与 JSF 相关的关于同一问题的答案中找到详细的解释:Spawning threads in a JSF managed bean for scheduled tasks using a timer。