7

我在本地机器上运行了一个 Tomcat 6 实例。

我对其配置进行了以下更改:

  • 在 /conf/ context.xml- 更改标签如下

    <Context crossContext="true">
    
  • 在 /conf/ server.xml - 更改标签如下

    <Connector port="8080" protocol="HTTP/1.1" emptySessionPath="true"
           connectionTimeout="20000" 
           redirectPort="8443" />
    

假设我有一个名为SampleProject.wardeploy here 的 WAR 文件,它提取到文件夹SampleProject

在这个 WAR 的一些 servlet 中,比如说SampleServlet,我写了两个代码块,如下所示:

ServletContext context1 = session.getServletContext();

ServletContext context2 = session.getServletContext().getContext("/SampleProject");

context1和 和有什么不一样context2?我认为两者都指应用程序上下文。但是,如果我在 中设置一些属性context1并访问context2,我不会在 中获得值context2

任何帮助,将不胜感激。

4

3 回答 3

5

我觉得你的问题有点被误解了,你已经对 API 有了基本的了解,即一旦网络应用程序设置了crossContext="true"它,它就可以getContext()用来访问与服务器上部署的其他一些网络应用程序相对应的上下文。

getServletContext().getContext() equals NULL unless <Context crossContext="true">

据我了解,您的问题实际上是/SameWebApp为什么

ServletContext context1 = session.getServletContext();
context1.setAttribute("contextAttribute", new Object());
ServletContext context2 = session.getServletContext().getContext("/SameWebApp");

System.out.println(context1.equals(context2)); // prints false, or 
System.out.println(context2.getAttribute("contextAttribute")); // prints null (at least they could have been clones)

一言以蔽之,答案是“安全”。想象一下,如果您不能保证“adminEmail”上下文属性没有具有crossContext=true. 一旦“忘记密码”请求出现,您的应用程序可能会帮助自己妥协!:)

深入了解 Tomcat 内部结构

Tomcat 7 提供了一个class ApplicationContext implements ServletContextgetContext("/context-root")as返回的

    if (context.getCrossContext()) {
        // If crossContext is enabled, can always return the context
        return child.getServletContext();
    } else if (child == context) {
        // Can still return the current context
        return context.getServletContext();
    } else {
        // Nothing to return
        return (null);
    }

这里context属于当前的 web-app,child代表另一个 web-app。但是,等等,是什么让 Tomcat 称它为孩子?

这两个实际上不是一个类的ApplicationContext实例,它不是 servlet 特定的东西,而是为 web 应用程序(如 crossContext、主机名、mimeMappings 等)保存 Tomcat 特定的配置设置,因此它被称为上面的子级.StandardContextimplements ContextStandardContext.getParent()Container

无论如何,我们感兴趣的情况是什么时候child == context为真,即getContext()在“/ SameWebApp ”上被调用。该调用被委派给StandardContext.getServletContext()已实现返回不同实例ApplicationContext.

这就是为什么你设置的属性context1context2.

但是等等,还有更多。为什么StandardContext.getServletContext()返回喜欢

return (context.getFacade());

一个 Tomcat 实例基本上执行两种类型的 Java 代码:

  • 提供的容器,和
  • 用户部署

容器代码是“受信任的”,有时可能需要以提升的权限运行。另一方面,用户代码不受信任,需要限制其破坏 Tomcat 内部。

Tomcat 为实现这一目标所做的其中一件事就是始终环绕ApplicationContextFacadeApplicationContext因此也是StandardContext如此)。因此,回顾一下,看似简单的ServletContext实现实际上是StandardContext映射到 anApplicationContext然后包装在ApplicationContextFacade.

有关如何将ApplicationContextFacade反射Globals.IS_SECURITY_ENABLEDSecurityUtil.isPackageProtectionEnabled()设置结合使用的更多信息,请查看为什么 Servlet 通过SO 上的 Facade 访问 Tomcat ApplicationContext。

参考:
Tomcat 7 源代码(下载链接)

于 2013-05-02T20:26:57.313 回答
3

Absolutely those two context objects are different from another.. Context1 object gives current web application servlet context obj. ( ServletContext context1 = session.getServletContext();)

and

context2 object gives the servletcontext obj of specified web application (ServletContext context2 = session.getServletContext().getContext("/SampleProject");)

you are setting object in one context and trying to retrieve using another context, so it is not possible to get attribute from another web application context by putting it in current application context. But you can get attribute resides in another web application context by using second method.

于 2013-04-06T03:14:28.890 回答
3

想想 OO 和 Java EE 平台标准 + 安全性。

第一次调用返回当前应用程序的最终servlet 上下文,支持所有操作。

第二个调用返回可以用于任何应用程序的 servlet 上下文的副本。正如 javadoc 中所说(相当模糊!),它的目的是让您获得 a RequestDispatcher,以便您可以分派到其他应用程序的页面。另一个主要但隐含的要求是安全地执行此操作并尊重 Java EE 规范,这些规范不允许在应用程序之间共享会话状态或 servlet 上下文。想象一下,如果“流氓应用程序 B”可以通过蛮力更改(或读取)Servlet 上下文数据,它会对“好的应用程序 A”造成可怕的损害。这就是为什么它是一个副本。

因此,在副本上设置属性不会导致对原件的更改。您可能会争辩说副本应该抛出一些“不支持的操作异常”。或者,您可以争辩说 getRequestDispatcher 应该重构为另一个类,或者允许传入 App Context URL。...但是,不幸的是,这些都不是真的。乙^)

于 2013-05-02T05:12:05.420 回答