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

35

我需要获取一些配置并连接到外部资源/对象/系统的某个位置,并将其存储在应用程序范围内。

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

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

上述哪种方法更好?是否有更好的方法来在servlet之间共享对象?直接相互调用还是如此...

1个回答

85

两者都没有更好的方法。Servlets旨在侦听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可用吗?在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并且无法升级,则选择其他方法。

如果您想知道如何在非JEE服务器(如Tomcat)上安装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.
    }
}

通过@EJB,可以在Servlet中使用此功能。与其他方法的区别在于默认情况下是事务性的,并且在@Singleton的情况下也是读/写锁定的。因此,如果您需要将随机EJB(例如@Stateless)注入到@WebListener@ApplicationScoped中,则可以将两者合并为单个@Startup @Singleton

另请参阅:


只是提醒,如果有人遇到类似的问题:似乎你必须在注册servlet之前在/WEB-INF/web.xml中注册<listener>。我不知道这一点。此外,GWT可能会出现注释方法的问题,因此最好手动注册<listener>而不是依赖注释,即使IDE没有给出错误。 - xji

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接