I would like to know if it’s ok to use Timer inside application scoped beans.
Example, lets say that I want to create a timer task that sends out a bunch of emails to every registered member one time per day. I’m trying to use as much JSF as possible and I would like to know if this is acceptable (it sounders a bit weird, I know).
Until now I have used all of the above inside a ServletContextListener. (I don’t want to use any application server or cron job and I want to keep
the above things inside my web app.)
Is there a smart JSF way of doing this or should I stick with the old pattern?
Introduction
As to spawning a thread from inside a JSF managed bean, it would only make sense if you want to be able to reference it in your views by
#{managedBeanName}or in other managed beans by@ManagedProperty("#{managedBeanName}"). You should only make sure that you implement@PreDestroyto ensure that all those threads are shut down whenever the webapp is about to shutdown, like as you would do incontextDestroyed()method ofServletContextListener(yes, you did?). See also Is it safe to start a new thread in a JSF managed bean?Never use
java.util.Timerin Java EEAs to using
java.util.Timerin a JSF managed bean, you should absolutely not use the old fashionedTimer, but the modernScheduledExecutorService. TheTimerhas the following major problems which makes it unsuitable for use in a long running Java EE web application (quoted from Java Concurrency in Practice):Timeris sensitive to changes in the system clock,ScheduledExecutorServiceisn’t.Timerhas only one execution thread, so long-running task can delay other tasks.ScheduledExecutorServicecan be configured with any number of threads.TimerTaskkill that one thread, thus makingTimerdead, i.e. scheduled tasks will not run anymore.ScheduledThreadExecutornot only catches runtime exceptions, but it lets you handle them if you want. Task which threw exception will be canceled, but other tasks will continue to run.Apart from the book quotes, I can think of more disadvantages:
If you forget to explicitly
cancel()theTimer, then it keeps running after undeployment. So after a redeploy a new thread is created, doing the same job again. Etcetera. It has become a “fire and forget” by now and you can’t programmatically cancel it anymore. You’d basically need to shutdown and restart the whole server to clear out previous threads.If the
Timerthread is not marked as daemon thread, then it will block the webapp’s undeployment and server’s shutdown. You’d basically need to hard kill the server. The major disadvantage is that the webapp won’t be able to perform graceful cleanup via e.g.contextDestroyed()and@PreDestroymethods.EJB available? Use
@ScheduleIf you target Java EE 6 or newer (e.g. JBoss AS, GlassFish, TomEE, etc and thus not a barebones JSP/Servlet container such as Tomcat), then use a
@SingletonEJB with a@Schedulemethod instead. This way the container will worry itself about pooling and destroying threads viaScheduledExecutorService. All you need is then the following EJB:This is if necessary available in managed beans by
@EJB:EJB unavailable? Use
ScheduledExecutorServiceWithout EJB, you’d need to manually work with
ScheduledExecutorService. The application scoped managed bean implementation would look something like this:where the
SomeDailyJoblook like this:If you don’t need to reference it in the view or other managed beans at all, then better just use
ServletContextListenerto keep it decoupled from JSF.