【问题标题】:ServletContext variable is not visible to other servletServletContext 变量对其他 servlet 不可见
【发布时间】:2017-05-24 20:04:13
【问题描述】:

假设我有两个 servlet,A 和 B。在 Servlet A 中,我创建一个 HashMap 并在 init() 中存储到 Servlet 上下文中,如下所示:

ServletContext context = getServletContext();
context.setAttribute("otable", someObject);

现在在 Servlet B 的 init() 中,我正在初始化对 servlet 上下文对象的本地引用(我正在指定首先创建 servlet 上下文对象的 servlet 以首先通过 web.xml 启动):

// get and set reference to object cache
oc = (ObjectCache)getServletContext().getAttribute("otable");

然后我插入,大小变为 1。当再次调用 Servlet A 并检查 servlet 上下文 HashMap 时,大小仍然为 0。

存储对 servlet 上下文对象的本地引用是不是一个坏主意?我也尝试直接从 servlet 上下文中获取对象,但得到了相同的结果。我在这里错过了什么?

创建共享对象的 servlet 首先在我的 web.xml 中使用以下内容启动:

<servlet>
<servlet-name>ServletA</servlet-name>
<servlet-class>package.ServletA</servlet-class>
<load-on-startup>0</load-on-startup>
</servlet>

【问题讨论】:

  • 啊,我明白了。谢谢马库斯,只是好奇,但在那种情况下,servlet 的局部变量不会与 servlet 上下文相同吗?或者 servlet 上下文是否用于同一个 servlet 的多个实例?使用并发哈希映射获取和放置两个 servlet 有什么问题吗?
  • 我删除了我的评论,因为它是错误的,对不起!
  • 你确定你的servlet已经初始化了吗?您可以在启动时设置负载。否则在第一个请求到达之前它们不会被初始化。是的,当您期望并发访问时,绝对不要使用 HashMap。它可能最终处于竞争状态!
  • 我编辑了问题以显示我的 web.xml 条目首先加载初始 servlet 的样子,这就是您所说的初始化吗?
  • 我是,从某种意义上说它是 ServletContext,因为我没有使用 Spring。这是你的意思吗?我曾认为 ServletContext 是可以在 Web 应用程序中的所有 servlet 之间共享某些东西的地方

标签: java servlets


【解决方案1】:

在 ServletContext 中存储跨 servlet 也就是应用程序范围的对象的想法是完全可行的。我重新测试了你的方法,它工作得很好。您一定错过了您忘记发布的代码中的某些内容。

我可以让它工作如下:

ServletA(片段):

public void init() throws ServletException {
    Map<String, String> map = new ConcurrentHashMap<>();
    getServletContext().setAttribute("map", map);
    System.out.println("Servlet A Mapsize: " + map.size());
    map.put("foo", "bar");
    System.out.println("Servlet A Mapsize: " + map.size());
}

protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    Map<String, String> map = (Map<String, String>) getServletContext().getAttribute("map");
    System.out.println("Servlet A Mapsize: " + map.size());
}

ServletB(片段):

public void init() throws ServletException {
    Map<String, String> map = (Map<String, String>) getServletContext().getAttribute("map");
    System.out.println("Servlet B Mapsize: " + map.size());
    map.put("foo", "bar");
    System.out.println("Servlet B Mapsize: " + map.size());
}

web.xml(截图):

<servlet>
    <servlet-name>ServletA</servlet-name>
    <servlet-class>mypackage.ServletA</servlet-class>
    <load-on-startup>0</load-on-startup>
</servlet>
<servlet>
    <servlet-name>ServletB</servlet-name>
    <servlet-class>mypackage.ServletB</servlet-class>
    <load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
    <servlet-name>ServletA</servlet-name>
    <url-pattern>/a</url-pattern>
</servlet-mapping>

启动应用程序会为您提供以下输出:

Servlet A Mapsize: 0

Servlet A Mapsize: 1

Servlet B 映射大小:1

Servlet B 映射大小:1

如您所见,地图已正确填充。

现在你可以调用 servletA 来检查是否一切正常。

在浏览器中打开(我的设置):

http://localhost:8080/servtest/a

将产生以下输出

Servlet A Mapsize: 1

顺便说一句,如果 CDI 可用,您可以编写 applicationScoped 缓存生成器以获得更易于维护的代码。

【讨论】:

    猜你喜欢
    • 2018-10-01
    • 1970-01-01
    • 2015-03-01
    • 2015-03-18
    • 1970-01-01
    • 1970-01-01
    • 2017-02-11
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多