jsf - util - timertask android
Engendrar hilos en un frijol administrado JSF para tareas programadas usando un temporizador (1)
Me gustaría saber si está bien usar el Timer
dentro de los beans con alcance de la aplicación.
Por ejemplo, digamos que quiero crear una tarea de temporizador que envíe un montón de correos electrónicos a cada miembro registrado una vez al día. Estoy tratando de usar tanto JSF como sea posible y me gustaría saber si esto es aceptable (suena un poco raro, lo sé).
Hasta ahora, he usado todo lo anterior en un ServletContextListener
. (No quiero usar ningún servidor de aplicaciones o trabajo cron y quiero mantener las cosas anteriores dentro de mi aplicación web).
¿Hay alguna forma inteligente de JSF de hacer esto o debería seguir con el viejo patrón?
Introducción
En cuanto a generar un hilo desde dentro de un bean gestionado JSF, solo tendría sentido si desea poder hacer referencia a él en sus vistas mediante #{managedBeanName}
o en otros beans gestionados por @ManagedProperty("#{managedBeanName}")
. Solo debe asegurarse de implementar @PreDestroy
para asegurarse de que todos esos hilos se cierren cuando la aplicación esté a punto de apagarse, como lo haría en el método contextDestroyed()
de ServletContextListener
(sí, ¿lo hizo?). Consulte también ¿Es seguro iniciar un nuevo hilo en un bean gestionado JSF?
Nunca use java.util.Timer
en Java EE
En cuanto al uso de java.util.Timer
en un bean gestionado JSF, no debe usar el Timer
antiguo, sino el moderno ScheduledExecutorService
. El Timer
tiene los siguientes problemas principales que lo hacen inadecuado para su uso en una aplicación web Java EE de larga ejecución (citada de Java Concurrency in Practice ):
-
Timer
es sensible a los cambios en el reloj del sistema,ScheduledExecutorService
no lo es. -
Timer
tiene solo un hilo de ejecución, por lo que la ejecución prolongada puede retrasar otras tareas.ScheduledExecutorService
se puede configurar con cualquier cantidad de subprocesos. - Cualquier excepción de tiempo de ejecución lanzada en un
TimerTask
mata ese hilo, haciendo que elTimer
TimerTask
, es decir, las tareas programadas ya no se ejecutarán.ScheduledThreadExecutor
no solo atrapa las excepciones de tiempo de ejecución, sino que le permite manejarlas si lo desea. La tarea que lanzó la excepción se cancelará, pero otras tareas continuarán ejecutándose.
Aparte de las citas de libros, puedo pensar en más desventajas:
Si olvida
cancel()
explícitamentecancel()
elTimer
, entonces sigue ejecutándose después del despliegue. Entonces, después de volver a implementar, se crea un nuevo hilo, haciendo el mismo trabajo nuevamente. Etcétera Se ha convertido en un "fuego y olvídate" por ahora y ya no puedes cancelarlo programáticamente. Básicamente, necesitaría apagar y reiniciar todo el servidor para borrar los hilos anteriores.Si el hilo del
Timer
no está marcado como hilo daemon, entonces bloqueará el despliegue de la webapp y el apagado del servidor. Básicamente necesitarías matar al servidor. La principal desventaja es que la aplicación web no podrá realizar una limpieza elegante mediante, por ejemplo,contextDestroyed()
y@PreDestroy
.
EJB disponible? Use @Schedule
Si se dirige a Java EE 6 o posterior (por ejemplo, JBoss AS, GlassFish, TomEE, etc. y, por lo tanto, no es un contenedor barebone JSP / Servlet como Tomcat), utilice un EJB @Singleton
con un método @Schedule
. De esta forma, el contenedor se preocupe por agrupar y destruir subprocesos a través de ScheduledExecutorService
. Todo lo que necesitas es entonces el siguiente 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.
}
}
Esto es necesario si está disponible en beans administrados por @EJB
:
@EJB
private BackgroundJobManager backgroundJobManager;
EJB no disponible? Use ScheduledExecutorService
Sin EJB, necesitaría trabajar manualmente con ScheduledExecutorService
. La implementación del bean administrado de la aplicación se vería así:
@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();
}
}
donde SomeDailyJob
ve así:
public class SomeDailyJob implements Runnable {
@Override
public void run() {
// Do your job here.
}
}
Si no necesita referenciarlo en la vista u otros beans administrados, mejor solo use ServletContextListener
para mantenerlo desacoplado de 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();
}
}