Java Spring Boot fat jar中存在NoClassDefFoundError,但依赖项在已编译的存档中,并且应用程序在IDE中运行良好

Java Spring Boot fat jar中存在NoClassDefFoundError,但依赖项在已编译的存档中,并且应用程序在IDE中运行良好,java,spring,maven,spring-boot,uberjar,Java,Spring,Maven,Spring Boot,Uberjar,更新:已解决 出于某种原因,我用来加载自定义类(扩展了GenModel)的类加载器没有已经加载的类的上下文,这是我没有预料到的。因此,即使GenModel是从我的调试角度加载的,它也不是从modelLoader的角度加载的 解决方案:URLClassLoader实例可以交给父上下文。我不知道该交给哪个上下文,只是检索了我知道已经加载的GenModel类的上下文,认为该上下文显然包含GenModel。所以,最后我只修改了一行代码: URLClassLoader modelLoader = new

更新:已解决

出于某种原因,我用来加载自定义类(扩展了
GenModel
)的类加载器没有已经加载的类的上下文,这是我没有预料到的。因此,即使
GenModel
是从我的调试角度加载的,它也不是从
modelLoader
的角度加载的

解决方案
URLClassLoader
实例可以交给父上下文。我不知道该交给哪个上下文,只是检索了我知道已经加载的
GenModel
类的上下文,认为该上下文显然包含
GenModel
。所以,最后我只修改了一行代码:

URLClassLoader modelLoader = new URLClassLoader(new URL[]{modelURL});
URLClassLoader modelLoader = new URLClassLoader(new URL[]{modelURL});
变成

URLClassLoader modelLoader = new URLClassLoader(new URL[]{modelURL},GenModel.class.getClassLoader());
URLClassLoader modelLoader = new URLClassLoader(new URL[]{modelURL},GenModel.class.getClassLoader());
这就解决了

向“邪恶蟾蜍”大声呼喊,他通过他的评论让我走上了正确的轨道

原版:

我正在构建一个原型,将编译的h2o神经网络模型作为web服务实现,并在运行时注入模型。该应用程序运行在SpringBoot嵌入式Tomcat服务器上,是一个Maven项目。我在Maven POM中有以下依赖项:

<dependency>
  <groupId>ai.h2o</groupId>
  <artifactId>h2o-genmodel</artifactId>
  <version>3.8.2.3</version>
</dependency>

这是我的POM:

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>TVGML</groupId>
    <artifactId>neuralnetpredictor</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>jar</packaging>
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <version>1.3.5.RELEASE</version>
                <executions>
                    <execution>
                        <goals>
                            <goal>repackage</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
    <dependencies>
        <dependency>
            <groupId>ai.h2o</groupId>
            <artifactId>h2o-genmodel</artifactId>
            <version>3.8.2.3</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
            <version>1.3.5.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger2</artifactId>
            <version>2.2.2</version>
            <scope>compile</scope>
        </dependency>
        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger-ui</artifactId>
            <version>2.2.2</version>
        </dependency>
    </dependencies>
    <properties>
        <java.version>1.8</java.version>
    </properties>
</project>

非常感谢您的任何见解

URLClassLoader实例可以被交给父上下文。由于不知道应该将其交给哪个上下文,我只是检索了我知道已经加载的GenModel类的上下文,我认为该上下文显然将包含GenModel。所以,最后我只修改了一行代码:

URLClassLoader modelLoader = new URLClassLoader(new URL[]{modelURL});
URLClassLoader modelLoader = new URLClassLoader(new URL[]{modelURL});
变成

URLClassLoader modelLoader = new URLClassLoader(new URL[]{modelURL},GenModel.class.getClassLoader());
URLClassLoader modelLoader = new URLClassLoader(new URL[]{modelURL},GenModel.class.getClassLoader());
这就解决了


向“邪恶蟾蜍”大声呼喊,他通过他的评论让我走上了正确的轨道

URLClassLoader实例可以被交给父上下文。由于不知道应该将其交给哪个上下文,我只是检索了我知道已经加载的GenModel类的上下文,我认为该上下文显然将包含GenModel。所以,最后我只修改了一行代码:

URLClassLoader modelLoader = new URLClassLoader(new URL[]{modelURL});
URLClassLoader modelLoader = new URLClassLoader(new URL[]{modelURL});
变成

URLClassLoader modelLoader = new URLClassLoader(new URL[]{modelURL},GenModel.class.getClassLoader());
URLClassLoader modelLoader = new URLClassLoader(new URL[]{modelURL},GenModel.class.getClassLoader());
这就解决了


向“邪恶蟾蜍”大声呼喊,他通过他的评论让我走上了正确的轨道

即使JAR出现在fat JAR中,它也会从清单中丢失吗?我怀疑
this.modelClassName
hex.genmodel.genmodel
,对吗?调用
modelLoader.loadClass
时会引发异常,对吗?(请提供更多详细信息,如更多带有行号的堆栈跟踪)。如果我的假设是正确的,那么问题可能在于
URLClassLoader
:它无法找到JAR。首先,我将试图理解在IDE中运行应用程序时,为什么在调试中应用程序可以工作。在这两种情况下,在创建
modelLoader
后放置一个断点,并尝试查找不同之处(可能是相对文件路径?)。清单只提到spring引导和我的主类。但是,还有许多其他依赖项工作正常,但没有提到。Manifest-Version:1.0 Archiver Version:Plexus Archiver构建者:NLUCERO开始类:com。-------research.machinelearning.neuralnets。NeuralNetService Spring引导版本:1.3.5.RELEASE创建人:Apache Maven Build Jdk:1.8.0_65主类:org.springframework.Boot.loader。JarLauncher@EvilToad. 不,模型类名<代码>此。模型类名是自定义生成的神经网络模型。在这种情况下,
deeplearning\u bcc078fd\u abba\u 4f9c\u 8e5b\u 7628051ddeda
。该类由URLClassLoader提供,令人惊讶的是,它运行良好。如前所述,此代码在Eclipse中运行良好。我尝试过的一件事是在代码的后面将演员阵容移动到(GenModel),以隔离您正在获得的东西。同样的问题依然存在。问题在于
hex.genmodel.genmodel
,而不是
this.modelClassName
(另一个类)。堆栈跟踪现在已发布。然后在Eclipse中调试时尝试检查
rawModel.getClass().getProtectionDomain().getCodeSource().getLocation()
。这应该给你类源的物理位置,并且,希望能让你知道为什么它在另一种情况下找不到类。即使JAR出现在胖JAR中,它也会从清单中丢失吗?我怀疑
This.modelClassName
hex.genmodel.genmodel
,对吗?调用
modelLoader.loadClass
时会引发异常,对吗?(请提供更多详细信息,如更多带有行号的堆栈跟踪)。如果我的假设是正确的,那么问题可能在于
URLClassLoader
:它无法找到JAR。首先,我将试图理解在IDE中运行应用程序时,为什么在调试中应用程序可以工作。在这两种情况下,在创建
modelLoader
后放置一个断点,并尝试查找不同之处(可能是相对文件路径?)。清单只提到spring引导和我的主类。但是,还有许多其他依赖项工作正常,但没有提到。Manifest-Version:1.0 Archiver Version:Plexus Archiver构建者:NLUCERO开始类:com。-------research.machinelearning.neuralnets。NeuralNetService Spring引导版本:1.3.5.RELEASE创建人:Apache Maven Build Jdk:1.8.0_65主类:org.springframework.Boot.loader。JarLauncher@EvilToad. 不,模型类名<代码>此。模型类名是自定义生成的神经网络模型。在这种情况下,
deeplearning\u bcc078fd\u abba\u 4f9c\u 8e5b\u 7628051ddeda
。该类由URLClassLoader提供,令人惊讶的是,它运行良好。如前所述,此代码在Eclipse中运行良好。我尝试过的一件事是在代码的后面将演员阵容移动到(GenModel),以隔离您正在获得的东西。同样的问题依然存在。问题出在他身上