Using special auto start servlet to initialize on startup and share application data

None of both is the better approach. Servlets are intended to listen on HTTP events (HTTP requests), not on deployment events (startup/shutdown).


CDI/EJB unavailable? Use ServletContextListener

@WebListener
public class Config implements ServletContextListener {

    public void contextInitialized(ServletContextEvent event) {
        // Do stuff during webapp's startup.
    }

    public void contextDestroyed(ServletContextEvent event) {
        // Do stuff during webapp's shutdown.
    }

}

If you're not on Servlet 3.0 yet and can't upgrade (it would be about time because Servlet 3.0 was introduced more than a decade ago), and thus can't use @WebListener annotation, then you need to manually register it in /WEB-INF/web.xml like below:

<listener>
    <listener-class>com.example.Config</listener-class>
</listener>

To store and obtain objects in the application scope (so that all servlets can access them), use ServletContext#setAttribute() and #getAttribute().

Here's an example which lets the listener store itself in the application scope:

    public void contextInitialized(ServletContextEvent event) {
        event.getServletContext().setAttribute("config", this);
        // ...
    }

and then obtain it in a servlet:

    protected void doGet(HttpServletRequest request, HttpServletResponse response) {
        Config config = (Config) getServletContext().getAttribute("config");
        // ...
    }

It's also available in JSP EL by ${config}. So you could make it a simple bean as well.


CDI available? Use @Observes on ApplicationScoped.class

import jakarta.enterprise.context.ApplicationScoped; // And thus NOT e.g. jakarta.faces.bean.ApplicationScoped

@ApplicationScoped
public class Config {

    public void init(@Observes @Initialized(ApplicationScoped.class) ServletContext context) {
        // Do stuff during webapp's startup.
    }

    public void destroy(@Observes @Destroyed(ApplicationScoped.class) ServletContext context) {
        // Do stuff during webapp's shutdown.
    }
}

This is available in a servlet via @Inject. Make it if necessary also @Named so it's available via #{config} in EL as well.

Noted should be that this is new since CDI 1.1. If you're still on CDI 1.0 and can't upgrade, then pick another approach.

In case you're curious how to install CDI on a non-JEE server such as Tomcat, head to: How to install and use CDI on Tomcat?


EJB available? Consider @Startup@Singleton

@Startup
@Singleton
public class Config {

    @PostConstruct
    public void init() {
        // Do stuff during webapp's startup.
    }

    @PreDestroy
    public void destroy() {
        // Do stuff during webapp's shutdown.
    }
}

This is available in a servlet via @EJB. The difference with other approaches is that it's by default transactional and in case of @Singleton also read/write locked. So if you would ever need to inject a random EJB (e.g. @Stateless) into a @WebListener or an @ApplicationScoped then you could basically as good merge both into a single @Startup @Singleton.

See also:

  • How to run a background task in a servlet based web application?
  • ServletContainerInitializer vs ServletContextListener
  • How do I force an application-scoped bean to instantiate at application startup?