34

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

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

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

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

4

1 回答 1

85

两者都不是更好的方法。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");
        // ...
    }

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


CDI 可用吗?使用@ObservesApplicationScoped.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.
    }
}

这在 servlet 中通过@Inject. 如有必要,也可以制作它,@Named以便它也可以通过#{config}EL 获得。

应该注意的是,这是自 CDI 1.1 以来的新功能。如果您仍在使用 CDI 1.0 并且无法升级,请选择另一种方法。

如果您对如何在 Tomcat 等非 JEE 服务器上安装 CDI 感到好奇,请前往:如何在 Tomcat 上安装和使用 CDI?


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

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

也可以看看:

于 2010-08-12T13:46:38.660 回答