【问题标题】:Difference between session.getServletContext() and session.getServletContext().getContext("/SampleProject")session.getServletContext() 和 session.getServletContext().getContext("/SampleProject") 的区别
【发布时间】:2013-03-26 14:32:40
【问题描述】:

我有一个 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.war 的 WAR 文件,该文件提取到文件夹 SampleProject

在这个 WAR 中的某个 servlet 中,比如 SampleServlet,我编写了如下两段代码:

ServletContext context1 = session.getServletContext();

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

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

任何帮助将不胜感激。

【问题讨论】:

    标签: java tomcat servlets


    【解决方案1】:

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

    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=trueevil web 应用程序篡改。一旦“忘记密码”请求出现,您的应用程序可能会帮助自己妥协! :)

    深入了解 Tomcat 内部

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

        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 属于当前网络应用,child 代表另一个网络应用。但是,等等,是什么让 Tomcat 称它为孩子?

    这两个实际上不是ApplicationContext,而是StandardContext 的实例@ 987654336@ 的类,但不是servlet 特定的东西,而是为Web 应用程序保存Tomcat 特定的配置设置,如crossContext、主机名、mimeMappings 等。@987654337 @ 给你Container,因此在上面它被称为一个孩子。

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

    这就是您在context1 中设置的属性在context2 中找不到的原因。

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

    return (context.getFacade());
    

    一个 Tomcat 实例基本上是在执行两种 Java 代码:

    • 提供容器,并且
    • 用户部署

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

    Tomcat 为实现这一目标所做的其中一件事是始终将ApplicationContextFacade 包裹在ApplicationContext 周围(因此也将StandardContext 包裹起来)。回顾一下,看似简单的ServletContext 实现实际上是一个StandardContext 映射到一个ApplicationContext,然后包装在一个ApplicationContextFacade 中。

    有关ApplicationContextFacade 如何将反射与Globals.IS_SECURITY_ENABLEDSecurityUtil.isPackageProtectionEnabled() 设置结合使用的更多信息,请查看SO 上的Why do Servlets access Tomcat ApplicationContext through a Facade

    参考:
    Tomcat 7 Source Code (Download Link)

    【讨论】:

      【解决方案2】:

      这两个上下文对象绝对是不同的.. Context1 对象提供当前 Web 应用程序 servlet 上下文 obj。 ( ServletContext context1 = session.getServletContext();)

      context2 对象给出指定 Web 应用程序的 servletcontext obj (ServletContext context2 = session.getServletContext().getContext("/SampleProject");)

      您在一个上下文中设置对象并尝试使用另一个上下文进行检索,因此无法通过将其放在当前应用程序上下文中从另一个 Web 应用程序上下文获取属性。但是您可以使用第二种方法获取属性驻留在另一个 Web 应用程序上下文中。

      【讨论】:

      • 但是 ServletContext context1 = session.getServletContext();在 SampleProject 中被调用,所以它不指向 SampleProject 的上下文吗?
      • 根据docs.oracle.com/javaee/6/api/javax/servlet/… - 不,此方法的目的是提供从当前 Web 应用的上下文访问当前 Web 服务器上其他 Web 应用的上下文。
      【解决方案3】:

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

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

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

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

      【讨论】:

        猜你喜欢
        • 2011-09-07
        • 2014-05-10
        • 2012-05-25
        • 1970-01-01
        • 2020-06-09
        • 1970-01-01
        • 1970-01-01
        • 2020-01-31
        • 2017-02-05
        相关资源
        最近更新 更多