gpt4 book ai didi

jsf - 使用计时器在 JSF 托管 bean 中为计划任务生成线程

转载 作者:行者123 更新时间:2023-11-28 23:28:49 25 4
gpt4 key购买 nike

我想知道是否可以在应用程序作用域的 bean 中使用 Timer

例如,假设我想创建一个定时任务,每天一次向每个注册成员(member)发送一堆电子邮件。我正在尝试尽可能多地使用 JSF,我想知道这是否可以接受(我知道这听起来有点奇怪)。

到目前为止,我已经在 ServletContextListener 中使用了上述所有内容。 (我不想使用任何应用程序服务器或 cron 作业,我想保留我的网络应用程序中的上述内容。)

是否有一种智能的 JSF 方法可以做到这一点,还是我应该坚持使用旧模式?

最佳答案

介绍

关于从 JSF 托管 bean 内部生成线程,只有如果您希望能够通过 #{managedBeanName} 在 View 中引用它才有意义> 或通过 @ManagedProperty("#{managedBeanName}") 在其他托管 bean 中.你应该只确保你实现了 @PreDestroy确保在 webapp 即将关闭时关闭所有这些线程,就像您在 contextDestroyed() 中所做的那样ServletContextListener的方法(是的,你做到了?)。另见 Is it safe to start a new thread in a JSF managed bean?

切勿在 Java EE 中使用 java.util.Timer

至于在 JSF 托管 bean 中使用 java.util.Timer,您应该绝对不要使用老式的 Timer,但是现代 ScheduledExecutorService . Timer 存在以下主要问题,这使得它不适合在长时间运行的 Java EE Web 应用程序中使用(引自 Java Concurrency in Practice):

  • Timer 对系统时钟的变化很敏感,ScheduledExecutorService 则不然。
  • Timer 只有一个执行线程,所以长时间运行的任务可以延迟其他任务。 ScheduledExecutorService 可以配置任意数量的线程。
  • TimerTask 中抛出的任何运行时异常都会杀死该线程,从而使 Timer 死亡,即计划任务将不再运行。 ScheduledThreadExecutor 不仅可以捕获运行时异常,还可以根据需要处理它们。抛出异常的任务将被取消,但其他任务将继续运行。

除了书上的引述,我还能想到更多的缺点:

  • 如果您忘记显式cancel() Timer,那么它会在取消部署后继续运行。因此,在重新部署后,将创建一个新线程,再次执行相同的工作。等等。它现在已经变成了“即刻执行”,您不能再以编程方式取消它了。您基本上需要关闭并重新启动整个服务器以清除以前的线程。

  • 如果 Timer 线程没有被标记为守护线程,那么它将阻止 webapp 的卸载和服务器的关闭。你基本上需要硬杀死服务器。主要的缺点是 webapp 将无法通过例如contextDestroyed()@PreDestroy 方法。

EJB 可用吗?使用 @Schedule

如果您的目标是 Java EE 6 或更新版本(例如 JBoss AS、GlassFish、TomEE 等,因此不是准系统 JSP/Servlet 容器,例如 Tomcat),则使用 @Singleton带有 @Schedule 的 EJB方法代替。这样容器就会担心通过 ScheduledExecutorService 汇集和销毁线程。您所需要的只是以下 EJB:

@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.
}

}

如有必要,可通过 @EJB 在托管 bean 中获得:

@EJB
private BackgroundJobManager backgroundJobManager;

EJB 不可用?使用 ScheduledExecutorService

如果没有 EJB,您需要手动使用 ScheduledExecutorService。应用程序范围内的托管 bean 实现看起来像这样:

@ManagedBean(eager=true)
@ApplicationScoped
public class BackgroundJobManager {

private ScheduledExecutorService scheduler;

@PostConstruct
public void init() {
scheduler = Executors.newSingleThreadScheduledExecutor();
scheduler.scheduleAtFixedRate(new SomeDailyJob(), 0, 1, TimeUnit.DAYS);
}

@PreDestroy
public void destroy() {
scheduler.shutdownNow();
}

}

SomeDailyJob 看起来像这样:

public class SomeDailyJob implements Runnable {

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

}

如果您根本不需要在 View 或其他托管 bean 中引用它,那么最好只使用 ServletContextListener使其与 JSF 分离。

@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);
}

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

}

关于jsf - 使用计时器在 JSF 托管 bean 中为计划任务生成线程,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33583772/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com