ServletContext
ServletContext 表示您的整个 Web 应用程序在 Servlet 容器中运行。正如Servlet spec 所承诺的,在servlet 处理第一个HTTP 请求之前建立上下文。 HttpSession 代表每个用户的工作会话(从技术上讲,是通过您的 servlet 代码的线程),ServletContext 代表所有这些用户的范围。
要挂钩到 servlet 上下文的设置和拆卸,请实现 ServletContextListener。提示:通过使用 @WebListener 注释标记它来自动部署您的侦听器。该接口需要一对方法,在处理第一个 Servlet 请求之前设置 Web 应用程序以及拆除 Web 应用程序时调用每个方法。
提示:这种拆卸方法是关闭ScheduledExecutorService 的好地方。与您的执行程序服务关联的线程可能会在您的 Web 应用程序结束后继续存在。您可能不希望这种情况发生。
看到这个问题:How to get and set a global object in Java servlet context
另请参阅 BalusC 的 this nice summary of Servlet scope。
获取 servlet 上下文
您可以通过首先访问其ServletConfig 来访问当前servlet 的ServletContext。
// … in your Servlet, such as its request handler methods like `doGet` …
ServletContext sc = this.getServletConfig().getServletContext() ;
那么在ServletContextListener 中,我们如何访问servlet 上下文?当调用侦听器上的两个方法中的任何一个时,都会传递一个ServletContextEvent。从那里拨打ServletContextEvent::getServletContext()。
将对象存储为 servlet 上下文中的“属性”
那么在哪里存储您的网络应用程序的全局变量,例如您的ScheduledExecutorService? servlet 上下文有一个从String 到Object 的内置映射。这些被称为“属性”。调用setAttribute( String , Object ) 存储属性映射。因此,为您的ScheduledExecutorService 起一个名称,以便在此地图中使用密钥。
ScheduledExecutorService sec = … ; // Instantiated somewhere in your code.
…
String key = "myScheduledExecutorServiceForXYZ" ;
sc.setAttribute( key , sec ); // Storing the executor service as a generic `Object` for use later.
稍后您可以以同样的方式获取您的ScheduledExecutorService。您需要从Object 转换为已知类,在本例中为ScheduledExecutorService。
Object o = sc.getAttribute( key ); // Fetch the `ScheduledExecutorService` from the servlet context’s built-in map of attributes.
// Cast to known class. If in doubt, test first with [`instanceOf`][11].
ScheduledExecutorService sec = ( ScheduledExecutorService ) o ;
您可以通过调用ServletContext::getAttributeNames 来获取所有存储属性名称的列表。
范围图
这是我的一个图表,用于了解 Servlet 环境中的范围层次结构。注意每一层作用域都有它的属性集,它自己的String 到Object 的映射。沿着图表向下看,每组属性的生命周期都较短。