Java 动态编译JSP(X)并将其包含在Web上下文根之外

Java 动态编译JSP(X)并将其包含在Web上下文根之外,java,jsp,tomcat,include,webcontext,Java,Jsp,Tomcat,Include,Webcontext,我有一个web应用程序大量使用jspx文件和jsp:include-includes,它们从同一个jar部署到tomcat中的数百个上下文中。目前,我们只能通过更改CSS或覆盖其他文件目录中的某些文件来修改每个实例的布局: 假设webapp.jar包含一个名为/css/forms.css的文件,那么webapp确保获得http://mydomain/cust1/res/css/forms.css已映射到该文件。如果webapp配置为在“覆盖目录”中查找,则如果存在名为/data/cust1/cs

我有一个web应用程序大量使用jspx文件和
jsp:include
-includes,它们从同一个jar部署到tomcat中的数百个上下文中。目前,我们只能通过更改CSS或覆盖其他文件目录中的某些文件来修改每个实例的布局:

假设webapp.jar包含一个名为
/css/forms.css
的文件,那么webapp确保获得
http://mydomain/cust1/res/css/forms.css
已映射到该文件。如果webapp配置为在“覆盖目录”中查找,则如果存在名为
/data/cust1/css/forms.css的文件,则此文件将从应用程序存档中的文件中提供。这是由webapp本身保证的

在过去的几年中,这是非常成功的,但最近我感觉到了或多或少的静态JSPX的限制带来的痛苦,这些限制不能被“覆盖”;)基本上,我希望能够为每个部署的上下文“覆盖”一些jspx文件,而无需为每个上下文编译和解压自定义webapp jar。(拥有一个定制的
something:includeJsp
-标记不会有问题)

基本上,webapp应该能够为单个jspx文件提供对jsp(x)编译器的覆盖,例如,查看以下示例:

<!-- webapp.jar:/jspx/view.jspx -->
<jsp:root ...>
  <ns:customInclude src="inc/include.jspx" />
</jsp:root>

<!-- webapp.jar:/jspx/inc/include.jspx -->
<jsp:root ...>
  Default-Markup from the webapp.jar
</jsp:root>

<!-- /data/cust1/jspx/inc/include.jspx -->
<jsp:root ...>
  Custom markup for "cust1"
</jsp:root>

webapp.jar中的默认标记
“cust1”的自定义标记
现在,当
http://.../cust1/jspx/view.jspx
被请求,我希望Tomcat编译并执行
/data/cust1/jspx/inc/include.jspx
。 基本上,我知道实际上所有必要的东西在Tomcat中都是可能的(从jspx编译成Java字节码,包括文件,…),但我也知道Tomcat/Jasper遵守jsp-spec。我通过查看代码发现这并不是那么容易


那么基本上,有人知道如何让这样的设置工作吗?也许有人已经解决了这个问题?或者有其他方法可以替代我目前的方法吗?

我最终实现了自己的
FileDirContext
,它是通过
context.xml
中的
-标记包含的。实际上,我实现了两个扩展,一个是
org.apache.naming.resources.WARDirContext
,另一个是
org.apache.naming.resources.FileDirContext
,因为我想在eclipse开发过程中启用相同的机制(部署到文件结构中)在我们的服务器上,这些服务器是从非分解的.war文件部署的

它们都可以通过上下文描述符进行配置,并且可以使用多个“虚拟覆盖”。覆盖可以是文件系统路径或外部.war文件(实际上更像是重命名为.war的.zip文件),也可以是打包到部署的.war文件中的.jar文件

使用一个虚拟覆盖的向下调整解决方案的步骤如下:

  • 创建一个类
    MagicWARContext
    (magic就像解决所有问题的方法;)从前面提到的
    WARDirContext
    扩展
  • 在此类中,创建一个静态内部类
    ProtectedMethodVisibleMaker extends FileDirContext
    。这允许访问Tomcat原始实现的某些受保护方法。覆盖
    doGetRealPath
    doLookup
  • 在您自己的WAR上下文中,为字段
    private String overlay
    和字段
    private ProtectedMethodVisibleMaker overlayContext
    创建getter和setter,并为此字段实例化一个新的空实例
  • 在WAR上下文调用的
    overlyContext.setDocBase(overlay)
    allocate()
    中。确保从
    release()
    调用
    overlyContext.release()
    ,以确保安全
  • 现在您必须重写另外5种
    WARDirContext
    • doGetRealPath(字符串)
    • doLookup(字符串)
    • getAttributes(名称,字符串[])
    • 列表(字符串)
    • 列表(名称)
      当然,
      列表
      的结果枚举应该包含虚拟覆盖的条目以及原始上下文。因此,我最终编写了自己的
      namingumeration
      ,它在委托命名枚举列表上迭代,并确保每个命名条目只输出一次
  • 从上下文描述符实例化魔术上下文:

    <Resources 
        className="package.name.tomcatextensions.MagicWARContext" 
        overlay="/data/some/dir"/>
    
    
    
  • 将您的类打包在一个jar中,并将其复制到
    tomcat/lib

  • 警告 我们正在重写Tomcat的内部类。这自然会使此代码暴露于更改中。因此,必须有人确保在版本升级后一切都按预期进行。代替一些受保护的方法,我们可以覆盖实际的公共方法,但其中一些是最终的,所以基本上你运气不好

    此外,还可以通过查找方法向其他应用程序层公开非魔法子上下文,这意味着它们不再具有该覆盖,或者不包含已部署war的后备资源。我最后在请求子文本时向日志中添加了一些警告。在启动过程中,这会发生两次,一次用于
    /WEB-INF/classes
    ,一次用于
    /WEB-INF/lib

    在我的用例中,我禁止添加包含这些路径中任何一个的虚拟覆盖,因为我不希望在我的web上下文中出现外部类文件,所以这不是问题。然而,其他一些客户端可能正在调用这些方法,并对它们执行一些意外的操作。在测试期间,我没有发现任何问题,但启用缓存或枚举资源时可能会出现奇怪的效果,并且在使用子上下文时会出现问题。。。当然,可以围绕查找返回的子文本创建虚拟包装,但我还没有这样做,因为我希望这是不必要的

    当然还有这个冰毒