使用特殊的自动启动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在应用程序启动时实例化?