Java 自定义Tomcat Webapp类加载器

Java 自定义Tomcat Webapp类加载器,java,tomcat,tomcat6,classloader,contextclassloader,Java,Tomcat,Tomcat6,Classloader,Contextclassloader,我正在尝试为tomcat实现一个自定义类加载器。我的第一次尝试产生了一个类强制转换异常(显然,tomcat试图将我的加载程序强制转换为org.apache.catalina.loader.WebappLoader)。很好,我扩展了WebappLoader并将catalina.jar添加到我的构建路径中 现在我已经准备好部署(我想)。我得到了这个错误: 严重:Catalina.start: 生命周期异常:开始:: java.lang.NoClassDefFoundError: org/apache

我正在尝试为tomcat实现一个自定义类加载器。我的第一次尝试产生了一个类强制转换异常(显然,tomcat试图将我的加载程序强制转换为org.apache.catalina.loader.WebappLoader)。很好,我扩展了WebappLoader并将catalina.jar添加到我的构建路径中

现在我已经准备好部署(我想)。我得到了这个错误:

严重:Catalina.start: 生命周期异常:开始:: java.lang.NoClassDefFoundError: org/apache/catalina/loader/WebappLoader

Tomcat随catalina.jar一起运行,因此我99.9%确定它已经加载到Tomcat中。我通过检查/server/lib/catalina.jar验证了这一点,它确实包含ApacheWebApploader。此外,如预期的那样,在中手动链接另一个catalina.jar会造成一大堆问题

我很困惑。任何提示都是热门的

谢谢


更新:有趣的是,在tomcat6上(扩展WebappLoader;在tomcat5.5上工作)同样的事情仍然会导致ClassCastException。在我看来,执行cast的类是使用与加载我的类的加载程序不同的加载程序加载的。我不知道我怎么能控制它,除非有另一个丢失的tomcat配置?对tomcat6也有什么想法吗?

如果不知道您的代码和设置的细节,就无法确定,但这让我想起了在尝试定制类加载器时遇到的一个问题

情况是这样的:

  • 引导加载程序(JVM-property/Tomcat/无论哪个)加载您的代码
  • 您的类加载器加载在上述类路径上不可用的添加内容
  • 您的代码引用了这些添加
  • 这些添加内容与引导加载程序加载的代码在同一命名空间中不可用
  • 启动加载程序名称空间中的代码运行,尝试引用自定义名称空间中的代码,但这在启动加载程序名称空间中不可见。因此,此时JVM将抛出NoClassDefFound错误
  • 原因是类加载器层次结构仅在一个方向上工作:即子名称空间(子类加载器)中的代码在更广泛的父名称空间(父类加载器)中不可用(可见);没有好办法侵入这个系统

    幸运的是,您可以定义在父命名空间中可用的接口,然后在仅在子命名空间中可见的代码中实现这些接口。然后,仅存在于父名称空间内的代码能够使用此接口名称进行强制转换和方法调用,从而访问子名称空间组件

    为了实现这一点,您必须确保您的自定义类加载器不仅加载父加载器无权访问的组件(即,在其类路径之外),而且加载直接与这些组件接口并显式引用这些符号(类型名/方法等)的代码位。否则,对这些组件的引用最终会出现在父命名空间中(请记住,引导类加载器默认情况下会加载您自己的所有代码),您将回到原始问题

    您可以通过颠覆预期的类加载委托模型来实现这一点。通常,在您自己尝试加载类之前,您将遵从父加载程序。但是,现在必须提前检查代码是否与父加载程序无法访问的任何组件接触。最简单的方法可能是设置代码路径,使类加载器维护一组类名称,而不是让父加载器自己加载它们

    您必须找到一种方法告诉您的自定义类加载器,类声明上的类型注释可以用于此目的。这里的想法是,您的类加载器会对父类加载的类进行内省,如果它在类型名称上找到一个特定的自定义注释,它将调用注释上的方法,以获取类符号的名称,该类符号不能允许其父类加载器加载

    例如:

    @MyCustomAnnotation(implementation="my.custom.package.MyImpl")
    public class MyFeatureProvider {
      public MyFeature getFeature() { // return an instance of MyImpl here }
    }
    

    请注意,由于类
    MyFeatureProvider
    将在
    MyImpl
    之前加载,因此类加载器将提前知道
    MyFeatureProvider
    中的注释,因此它将能够覆盖MyImpl的默认委派模型。因为您的代码的其余部分只与
    MyImpl
    作为
    MyFeature
    的一个实例进行交互,所以父加载程序在看到未定义的符号时从不需要犹豫——ClassNoDefFound错误就解决了。

    也许我是很密集,但我认为应该是WebappClassLoader,而不是WebappLoader。不过导入看起来还可以。

    OMG;真不敢相信我这么做了。非常感谢。现在工作。