Skip to main content
 首页 » 编程设计

servlets之使用特殊的自动启动 servlet 在启动时进行初始化并共享应用程序数据

2024年09月07日12haluo1

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

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

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

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

    请您参考如下方法:

    两者都不是更好的方法。 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 可用吗?使用 @Observes 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. 
        } 
    } 
    
    这可以通过 @Inject 在 servlet 中使用。 .如有必要,也可以 @Named所以它可以通过 #{config}获得在 EL 中也是如此。
    应该注意的是,这是自 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 )注入(inject) @WebListener@ApplicationScoped那么您基本上可以将两者合并为一个 @Startup @Singleton .
    也可以看看:
  • 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?