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

riz*_*riz 32 servlets initialization data-sharing

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

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

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

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

Bal*_*usC 74

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


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

}
Run Code Online (Sandbox Code Playgroud)

如果你还没有使用Servlet 3.0并且无法升级,因而无法使用@WebListener注释,那么你需要手动注册它,/WEB-INF/web.xml如下所示:

<listener>
    <listener-class>com.example.Config</listener-class>
</listener>
Run Code Online (Sandbox Code Playgroud)

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

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

    public void contextInitialized(ServletContextEvent event) {
        event.getServletContext().setAttribute("config", this);
        // ...
    }
Run Code Online (Sandbox Code Playgroud)

然后在servlet中获取它:

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

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


CDI可用吗?使用@ObservesApplicationScoped.class

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.
    }
}
Run Code Online (Sandbox Code Playgroud)

这可以在servlet via中找到@Inject.如有必要,也@Named可以通过#{config}EL 获得它.

值得注意的是,自CDI 1.1以来,这是新的.如果你仍然使用CDI 1.0并且无法升级,那么选择另一种方法.


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.
    }
}
Run Code Online (Sandbox Code Playgroud)

这也可以通过#{config}EL获得.


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.
    }
}
Run Code Online (Sandbox Code Playgroud)

这可以在servlet via中找到@EJB.我说"考虑",因为你不应该为了启动钩子滥用EJB.此外,a @Singleton默认是读/写锁定,主要用于事务性事务,例如调度后台作业.

也可以看看: