Caveat: This Answer addresses the app servers such as Apache Tomcat and Eclipse Jetty that do not implement the Jakarta Concurrency specification. That spec defines “managed” executor services and the annotation @Schedule
. Users of “Full Platform” Jakarta such as JBoss/WildFly, Glassfish/Payara, and so on (list) should use that facility for a much simpler and easier approach to scheduling tasks.
ServletContextListener
A Servlet runs only when a Request arrives from a user. Set-up tasks such as your scheduler must be done before that first Request is handled.
That is the purpose of the ServletContextListener interface. The term “Servlet context” simply means your web app. The "listener" part means a class implementing this interface will be called automatically.
Specifically, either of two methods will be called. One method is called when your web app is deployed, another when your web app is being shutdown. Use one to launch your ScheduledExecutorService
. Use the other to terminate your ScheduledExecutorService
. Very important to terminate, as your executor’s thread pool may continue running, long after your web app has stopped, and even after your web container closed.
When you write your class implementing this interface, you can use different avenues for its deployment. The easiest avenue is to mark the class with the @WebListener annotation. Your web container will automatically detect such a marked class and load it. After the Web container has finished initializing your web app, but before the first incoming Request is handled, your ServletContextListener
will be invoked. This behavior is guaranteed by the Servlet spec version 2.3 and later. So it works across all Web containers: Tomcat, Jetty, TomEE, Glassfish, JBoss, WildFly, etc.
The ServletContextListener
architecture was a wise addition to the Servlet, crucial for more serious web apps. The design is generally good but lacks one important feature: If something fails during your setup, there is no way for your listener to halt the deployment of your web app. If your database is down, or needed web services unreachable, or other important resources unavailable, you may not want your Web app to commence. The Servlet spec fails to address this need. A workaround is to somehow communicate between your listener and your servlet, perhaps set some flag in the context “attributes” and check for that flag within your servlet.
I gave a talk on this subject of ServletContextListener at Devoxx Morocco 2017. Some of my slides are shown above, the entire slide deck is available as a PDF.