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

前端 未结 1 786
生来不讨喜
生来不讨喜 2020-11-21 11:40

I need to get some configuration and connect to external resources/objects/systems somewhere and store it in application scope.

I can see two ways to setup my applic

相关标签:
1条回答
  • 2020-11-21 11:52

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


    CDI/JSF/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, 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 javax.enterprise.context.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.


    JSF available? Use @ManagedBean(eager=true)

    import javax.faces.bean.ManagedBean
    import javax.faces.bean.ApplicationScoped;
    
    @ManagedBean(eager=true)
    @ApplicationScoped
    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 via #{config} in EL as well.


    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. I'm saying "consider", because you should not abuse an EJB for the sake of a startup hook. Moreover, a @Singleton is by default read/write locked and primarily intented for transactional stuff such as scheduling background jobs.

    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?
    0 讨论(0)
提交回复
热议问题