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

我需要获得一些configuration,并连接到外部资源/对象/系统,并将其存储在应用程序范围内。

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

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

以上哪个更好? 有什么更好的方式来分享Servlet之间的对象? 直接打电话给他们…?

两者都不是更好的方法。 Servlet用于监听HTTP事件(HTTP请求),而不是监听部署事件(启动/closures)。


CDI / JSF / 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都可以访问它们),请使用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。

如果你还没有使用Servlet 3.0并且不能升级,并且不能使用@WebListener注解,那么你需要像下面那样在/WEB-INF/web.xml手动注册它:

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

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

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

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

值得注意的是,自从CDI 1.1以来,这是新的。 如果您还在CDI 1.0上,并且无法升级,请select其他方法。


JSF可用? 使用@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. } } 

这也可以通过EL中的#{config}来使用。


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中可用。 我在说“考虑”,因为你不应该为了启动钩子而滥用EJB。 此外,默认情况下@Singleton是读/写locking的,主要用于事务处理,如调度后台作业。

也可以看看:

  • 如何在基于servlet的Web应用程序中运行后台任务?
  • ServletContainerInitializer vs ServletContextListener
  • 如何强制应用程序范围的bean在应用程序启动时实例化?