Spring 部署在带有 Insight 的 tc 服务器中时,应用程序启动失败并出现 NoClassDefFoundError

Spring application fails on startup with NoClassDefFoundError when deployed in tc Server with Insight

我有一个基于 Spring 的应用程序(打包成 WAR),它在 Jetty 和 "ordinary" Tomcat 7 中运行良好,但是当它运行时会产生奇怪的 NoClassDefFoundError使用 Spring Insight 部署到 tc 服务器。它抱怨找不到的 class 肯定在 WEB-INF/lib 文件夹中的一个 JAR 中(我已经仔细检查 Tomcat 共享库文件夹中不存在竞争的 JAR ).

这是堆栈跟踪,显示 Spring 认为它无法找到 class HierarchicalLoop:

java.lang.ClassNotFoundException: com.foo.HierarchicalLoop<com.foo.Loop>
    at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1714) ~[na:na]
    at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1559) ~[na:na]
    ... 32 common frames omitted
Wrapped by: java.lang.NoClassDefFoundError: com/foo/HierarchicalLoop<com/foo/Loop>
    at java.lang.Class.getDeclaredConstructors0(Native Method) ~[na:1.7.0_60]
    at java.lang.Class.privateGetDeclaredConstructors(Class.java:2532) ~[na:1.7.0_60]
    at java.lang.Class.getConstructor0(Class.java:2842) ~[na:1.7.0_60]
    at java.lang.Class.getDeclaredConstructor(Class.java:2053) ~[na:1.7.0_60]
    at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:80) ~[spring-beans-4.1.6.RELEASE.jar:4.1.6.RELEASE]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateBean(AbstractAutowireCapableBeanFactory.java:1094) ~[spring-beans-4.1.6.RELEASE.jar:4.1.6.RELEASE]
    ... 26 common frames omitted
Wrapped by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'x12Builder' defined in class path resource [spring/x12-builder-config.xml]: Instantiation of bean failed; nested exception is java.lang.NoClassDefFoundError: com/foo/HierarchicalLoop<com/foo/X12Loop>
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateBean(AbstractAutowireCapableBeanFactory.java:1101) ~[spring-beans-4.1.6.RELEASE.jar:4.1.6.RELEASE]

如果我在服务器实例中禁用 Insight,应用程序加载正常,并且可以在 3 台不同的机器上重现。正如我所说,WAR 也可以在 Jetty 和 Tomcat(没有 Insight)下正确加载。所以我很确定它已经缩小到 Insight 所做的事情。

根据我的经验,这些神秘的 NoClassDefFoundErrorClassNotFoundException 错误通常是由 class 加载程序混淆引起的。例如,容器的根 classloader 试图从应用程序 JAR 加载 classes。但在这种情况下,Insight 对我来说是一个黑盒子,我不确定它在幕后做了什么。我怀疑 Spring classes 可能来自 classloader 而不是我的应用程序的 classloader,这可以解释为什么 Spring 看不到来自应用程序 lib 中 JAR 的 classes。但这只不过是有根据的猜测,即使它是准确的我也不知道如何解决它。

任何有关故障排除的想法或对 Insight 工作原理的见解都将受到赞赏。

事实证明,这是由于 Insight 中的某种限制或错误造成的。它抱怨的 class HierarchicalLoop<Loop> 导致 Insight classloader (TomcatWeavingInsightClassLoader) 出现问题,这使得它报告为 ClassNotFoundException。它与类型参数有关;这是导致 class 加载程序问题的两个 classes:

public class Loop<ChildType extends Loop> {
    //...
}

public class HierarchicalLoop<ChildType extends Loop> extends Loop<ChildType> {
    //...
}

这是完全有效的 Java,其他 containers/classloaders(Tomcat、Jetty、JUnit)在加载这些 class 时没有任何问题。但出于某种原因,Insight 确实如此。

HierarchicalLoop 的子class,但它们都只是将 Loop 指定为 ChildType 参数,因此实际上不需要该参数。所以我能够通过从 HierarchicalLoop :

中删除类型参数来解决这个问题
public class HierarchicalLoop extends Loop<Loop> {
    //..
}

我很确定这是 Insight 中的错误;我想报告它,但找不到任何社区支持或错误报告渠道。