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

zig*_*ggy 1 java session tomcat servlets

我正在尝试编写一个简单的程序,我可以在应用程序范围的会话中放置HashMap,并获得两个应用程序/上下文,因为两个war文件访问HashMap.

Servlet 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);   
    }
Run Code Online (Sandbox Code Playgroud)

Servlet 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());   
}
Run Code Online (Sandbox Code Playgroud)

为了测试这一点,我重新启动了Tomcat 6,然后首先运行访问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)
Run Code Online (Sandbox Code Playgroud)

hom*_*ome 7

正如@Peter Cetinski已经提到的,Servlet Context总是与一个Web应用程序(WAR文件)完全相关.尽管如此,Servlet API提供了一种通过调用来访问"外部"Servlet上下文的方法javax.servlet.ServletContext.getContext(uriPath).

因此,如果您真的希望/需要将Servlet分布在不同的WAR上并且需要它们之间的通信,那么您可以这样做.

假设的Servlet 1位于web应用,Servlet的2位于web应用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");
Run Code Online (Sandbox Code Playgroud)

有一些限制:

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

  • 这个设置是专有的(我无法告诉你它在其他应用服务器/ servlet引擎中是如何工作的)

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

  • 在标准设置你与不同的类加载器的工作warAwarB,你应该知道的是

  • Tomcat不保证某个启动序列(没有办法配置它).在你的情况下warB必须能够处理这个并期望warA尚未开始

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

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

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

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