java - 使用 Servlet 上下文让两个 servlet 使用同一个对象

标签 java session tomcat servlets

我正在尝试编写一个简单的程序,我可以在其中将 HashMap 放在应用程序范围的 session 上,并在两个 war 文件访问 HashMap 时部署两个应用程序/上下文。

小服务程序 1

public void doGet(HttpServletRequest request, HttpServletResponse response)
    throws IOException{
        PrintWriter out = response.getWriter();

        HashMap<String ,String> hm = new HashMap<String, String>();
        hm.put("1", "1");

        this.getServletContext().setAttribute("usermanager", hm);
        this.getServletConfig().getServletContext().setAttribute("usermanager2", hm);   
    }

小服务程序 2

public void doGet(HttpServletRequest request, HttpServletResponse response)
throws IOException{

    HashMap newMap2 = (HashMap) this.getServletConfig().getServletContext().getAttribute("usermanager"); 
    HashMap newMap3 = (HashMap) this.getServletContext().getAttribute("usermanager2"); 

    System.out.println("newmap2 size " + newMap2.size());
    System.out.println("newmap3 size " + newMap3.size());   
}

为了对此进行测试,我重新启动了 Tomcat 6,然后首先运行 access Servlet 1,以便它初始化 Hashmap 对象。当我随后访问 Servlet 2 时,我得到一个 NULL-POINTER 错误,它指向我试图调用 newMap2.size() 的行号

我做错了什么?

java.lang.NullPointerException
    at com.TestServlet.doGet(TestServlet.java:24)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:617)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:717)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:290)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:233)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:191)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:127)
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102)
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:291)
    at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:859)
    at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:602)
    at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:489)
    at java.lang.Thread.run(Thread.java:619)

最佳答案

正如@Peter Cetinski 已经提到的,Servlet 上下文总是只与一个 Web 应用程序(WAR 文件)相关。然而,Servlet API 提供了一种通过调用 javax.servlet.ServletContext.getContext(uriPath) 访问“外部”Servlet 上下文的方法。 .

因此,如果您真的想要/需要将您的 Servlet 分布在不同的 WAR 中并且需要它们之间的通信,您可以这样做。

假设Servlet 1位于网络应用程序warA中,Servlet 2位于网络应用程序warB中,并且应用程序上下文路径与 Web 应用程序名称相同(例如 http://myserver/warAhttp://myserver/warB ),Servlet 2 的代码可能如下所示:

/* retrieve foreign context */
ServletContext ctxWarA = this.getServletContext().getContext("warA");

/* ... and work with it */
Map<String, String> map = (Map<String, String>) ctxWarA.getAttribute("usermanager");

有一些限制:

  • 您必须明确允许 warB通过在应用程序的 context.xml 中指定它来访问外部上下文: <Context crossContext="true"/>

  • 此设置是专有的(我无法告诉您它在其他应用程序服务器/servlet 引擎中的工作原理)

  • 如果您想共享自定义类,它们必须在应用程序之间共享(将它们放在 <tomcat>/lib

  • 在标准设置中,您使用不同的类加载器来处理 warAwarB ,你应该知道这一点

  • Tomcat 不保证一定的启动顺序(没有办法配置这个)。在你的情况下 warB必须能够处理这个并期待 warA还没开始

如果您需要在 Web 应用程序之间共享对象/信息,我会考虑这些替代方法:

  • 位于 Tomcat/lib 中的共享单例(我知道一个单例,但它有效)

  • 位于 JNDI 树 ( Tomcat documentation ) 中的对象

  • 在共享数据存储(文件、数据库等)中构建缓存所需的信息以及每个应用程序在启动时加载数据

关于java - 使用 Servlet 上下文让两个 servlet 使用同一个对象,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9446225/

相关文章:

java - 更改/检查值的更好方法是什么?

php - 如何增加 Symfony2 中的 session 生命周期?

python - 如何使用 Python 实现用户身份验证和 session

tomcat - 设置Tomcat的RECYCLE_FACADES = true的缺点?

java - 在 JDK 为 64 位的基于 Web 的应用程序中使用 Tesseract

java - 使用preparestatement时链接到另一个应用程序

java - FQL 查询在接下来的 30 天内使用 Android 获取 Facebook friend 的生日

java - 无法在 java 中正确覆盖 keyPressed(KeyEvent)

php - 将 HTML 表单值作为数组放入 SESSION 变量中

php - mysqli_connect() 不适用于 PHP 和 Tomcat