【问题标题】:Using special auto start servlet to initialize on startup and share application data使用特殊的自动启动 servlet 在启动时进行初始化并共享应用程序数据
【发布时间】:2011-03-28 22:39:33
【问题描述】:

我需要进行一些配置并在某处连接到外部资源/对象/系统并将其存储在应用程序范围内。

我可以看到两种设置我的应用程序的方法:

  • 覆盖现有 servlet 中的 init() 和所需的代码,并将所有构造的对象保留在同一个 servlet 中。
  • 拥有某种初始化 servlet 并使用它的init() 来完成这项工作。然后将创建的对象存储在 ServletContext 中,以便与我的其他 servlet 共享。

以上哪种方法更好?有没有更好的方法在 servlet 之间共享对象?直接从彼此之间调用它们......?

【问题讨论】:

    标签: servlets initialization data-sharing


    【解决方案1】:

    两者都不是更好的方法。 Servlet 旨在侦听 HTTP 事件(HTTP 请求),而不是部署事件(启动/关闭)。


    CDI/EJB 不可用?使用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.
        }
    
    }
    

    如果您还没有使用 Servlet 3.0 并且无法升级(因为 Servlet 3.0 是十多年前推出的,这将是时候了),因此无法使用 @WebListener 注释,那么您需要在/WEB-INF/web.xml 中手动注册,如下所示:

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

    要在应用程序范围内存储和获取对象(以便所有 servlet 都可以访问它们),请使用 ServletContext#setAttribute()#getAttribute()

    这是一个让监听器将自身存储在应用程序范围内的示例:

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

    然后在 servlet 中获取它:

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

    ${config} 也可以在 JSP EL 中使用它。所以你也可以让它成为一个简单的 bean。


    CDI 可用吗?在ApplicationScoped.class 上使用@Observes

    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.
        }
    }
    

    这可以通过@Inject 在servlet 中使用。如有必要,也可以使用@Named,这样它也可以通过 EL 中的#{config} 获得。

    值得注意的是,这是自 CDI 1.1 以来的新功能。如果您仍在使用 CDI 1.0 并且无法升级,请选择其他方法。

    如果您对如何在 Tomcat 等非 JEE 服务器上安装 CDI 感到好奇,请访问:How to install and use CDI on Tomcat?


    EJB 可用吗?考虑@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.
        }
    }
    

    这可以通过@EJB 在servlet 中使用。与其他方法的不同之处在于它默认是事务性的,并且在@Singleton 的情况下也读/写锁定。因此,如果您需要将随机 EJB(例如 @Stateless)注入到 @WebListener@ApplicationScoped 中,那么您基本上可以将两者合并到一个 @Startup @Singleton 中。

    另见:

    【讨论】:

    • 如果有人遇到类似问题,请注意:似乎您必须在注册 servlet 之前在 /WEB-INF/web.xml 中注册 &lt;listener&gt;。我不知道。此外,GWT 可能在注解方法上存在问题,因此最好手动注册&lt;listener&gt;,而不是依赖注解,即使 IDE 没有给出错误。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-09-06
    • 1970-01-01
    • 2013-12-23
    • 2011-12-08
    • 2011-11-17
    • 1970-01-01
    相关资源
    最近更新 更多