我正在尝试编写一个简单的程序,我可以在其中将 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/warA
和 http://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
在标准设置中,您使用不同的类加载器来处理
warA
和warB
,你应该知道这一点Tomcat 不保证一定的启动顺序(没有办法配置这个)。在你的情况下
warB
必须能够处理这个并期待warA
还没开始
如果您需要在 Web 应用程序之间共享对象/信息,我会考虑这些替代方法:
位于 Tomcat/lib 中的共享单例(我知道一个单例,但它有效)
位于 JNDI 树 ( Tomcat documentation ) 中的对象
在共享数据存储(文件、数据库等)中构建缓存所需的信息以及每个应用程序在启动时加载数据
关于java - 使用 Servlet 上下文让两个 servlet 使用同一个对象,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9446225/