【问题标题】:Gradle multi module project java.lang.NoClassDeffFoundErrorGradle 多模块项目 java.lang.NoClassDeffFoundError
【发布时间】:2020-11-10 16:49:40
【问题描述】:

我有以下简单的测试项目结构

 |TestProject
 |
 |---project-a
 |   |---src
 |       |---main
 |           |---java
 |               |---package-name.ProjectA
 |                   |---service
 |                   |   |---TestService.java
 |                   |
 |                   |---ProjectAServiceApplication.java
 |
 |---project-b
 |   |---src
 |       |---main
 |           |---java
 |               |---package-name.ProjectB
 |                   |---enums
 |                       |---Commodity.java
 |
 |---build.gradle
 |---settings.gradle

build.gradle 看起来像

import com.commercehub.gradle.plugin.avro.GenerateAvroJavaTask
import groovy.json.*

buildscript {
    ext {
        springCloudVersion =  'Greenwich.RELEASE'
        springBootVersion =  '2.1.2.RELEASE'
    }

    repositories {
        mavenCentral()
        jcenter()
        maven {
            url "http://packages.confluent.io/maven"
        }
        maven { url 'https://repo.spring.io/milestone' }
        maven { url 'https://projectlombok.org/edge-releases' }

    }
    dependencies {
        classpath "org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}"
        classpath "com.commercehub.gradle.plugin:gradle-avro-plugin:0.14.2"
        classpath "net.ltgt.gradle:gradle-apt-plugin:0.21"
    }
}

plugins {
    id "net.ltgt.apt" version "0.21" apply false
    id "io.spring.dependency-management" version "1.0.8.RELEASE"
}

subprojects {

    // Packer variables
    ext {
        packerVariablesFolder = "$buildDir/packer"
        packerVariablesPath = "$packerVariablesFolder/$packerVariables"
        packerTemplateFolder = "../config"
        packerTemplatePath = "$packerTemplateFolder/$packerTemplate"
    }

    apply plugin: 'idea'
    apply plugin: 'io.spring.dependency-management'
    apply plugin: 'java'
    apply plugin: 'java-library'
    apply plugin: 'org.springframework.boot'

    group = 'de.SWS.PLM'
    version = '0.0.1-SNAPSHOT'
    sourceCompatibility = '11'

    repositories {
        mavenCentral()
        jcenter()
        maven {
            url "http://packages.confluent.io/maven"
        }
        maven { url 'https://repo.spring.io/milestone' }
        maven { url 'https://projectlombok.org/edge-releases' }
    }

    springBoot {
        buildInfo()
    }

    dependencyManagement {
        imports {
            mavenBom "org.springframework.cloud:spring-cloud-dependencies:${springCloudVersion}"
        }
    }

    ext.convertProjectName = { ->
        return project.name.split("(?<!(^|[A-Z]))(?=[A-Z])|(?<!^)(?=[A-Z][a-z])").join("-").toLowerCase()
    }

    dependencies {
        implementation 'org.springframework.boot:spring-boot-starter-actuator'
        compile group: 'log4j', name: 'log4j', version: '1.2.17'
        compile 'org.apache.commons:commons-lang3:3.10'
        compileOnly 'org.projectlombok:lombok:1.18.10'
        annotationProcessor 'org.projectlombok:lombok:1.18.10'
        testImplementation 'org.springframework.boot:spring-boot-starter-test'
    }

    task defineBuildVersion {
        if (project.hasProperty("revision")) {
            ext.imageVersion = version + "-${revision}"
        } else {
            ext.imageVersion = version + "-SNAPSHOT"
        }
    }

    compileJava {
        //raise heap
        options.fork = 'true'
        options.forkOptions.with {
            memoryMaximumSize = '2048m'
        }
    }

    task generatePackerFiles {
        doLast {
            mkdir "$packerVariablesFolder"
            new File("$packerVariablesPath").text = JsonOutput.toJson([
                    jar_file: jar.archiveName,
                    logback_file: "logback-pfm.xml",
                    image_name: "$convertProjectName",
                    image_tag: "${defineBuildVersion.imageVersion}"
            ])
        }
    }

    task buildDockerImage(type: Exec) {
        dependsOn generatePackerFiles
        commandLine 'packer', 'build', "-var-file=${packerVariablesPath}", "${packerTemplatePath}"
    }

    compileJava {
        //raise heap
        options.fork = 'true'
        options.forkOptions.with {
            memoryMaximumSize = '2048m'
        }
    }

    task cleanIntellijDirs(type: Delete) {
        delete 'out'
    }
}

configure(subprojects.findAll { !['project-b'].contains(it.name)} ) {
    dependencies {
        implementation project(':project-b')
    }
}

settings.gradle 看起来像

rootProject.name = 'TestProject'

include 'project-a'
include 'project-b'

如果我为 project-a gradle :project-a:build 运行 gradlew 任务构建,它会正确构建项目并生成 *.jar 文件。 如果我执行 *.jar 文件,我会得到以下输出

org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'testService' defined in URL [jar:file:/C:/Users/sws-216/Documents/Projekte/pfm-project/TestProject/project-a/build/libs/project-a-0.0.1-SNAPSHOT.jar!/BOOT-INF/classes!/de/SWS/PLM/ProjectA/service/TestService.class]: Instantiation of bean failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [de.SWS.PLM.ProjectA.service.TestService]: Constructor threw exception; nested exception is java.lang.NoClassDefFoundError: de/SWS/PLM/Commodity
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateBean(AbstractAutowireCapableBeanFactory.java:1270) ~[spring-beans-5.1.4.RELEASE.jar!/:5.1.4.RELEASE]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1164) ~[spring-beans-5.1.4.RELEASE.jar!/:5.1.4.RELEASE]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:538) ~[spring-beans-5.1.4.RELEASE.jar!/:5.1.4.RELEASE]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:498) ~[spring-beans-5.1.4.RELEASE.jar!/:5.1.4.RELEASE]
        at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:320) ~[spring-beans-5.1.4.RELEASE.jar!/:5.1.4.RELEASE]
        at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222) ~[spring-beans-5.1.4.RELEASE.jar!/:5.1.4.RELEASE]
        at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:318) ~[spring-beans-5.1.4.RELEASE.jar!/:5.1.4.RELEASE]
        at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) ~[spring-beans-5.1.4.RELEASE.jar!/:5.1.4.RELEASE]
        at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:846) ~[spring-beans-5.1.4.RELEASE.jar!/:5.1.4.RELEASE]
        at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:863) ~[spring-context-5.1.4.RELEASE.jar!/:5.1.4.RELEASE]
        at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:546) ~[spring-context-5.1.4.RELEASE.jar!/:5.1.4.RELEASE]
        at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:775) ~[spring-boot-2.1.2.RELEASE.jar!/:2.1.2.RELEASE]
        at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:397) ~[spring-boot-2.1.2.RELEASE.jar!/:2.1.2.RELEASE]
        at org.springframework.boot.SpringApplication.run(SpringApplication.java:316) ~[spring-boot-2.1.2.RELEASE.jar!/:2.1.2.RELEASE]
        at org.springframework.boot.SpringApplication.run(SpringApplication.java:1260) ~[spring-boot-2.1.2.RELEASE.jar!/:2.1.2.RELEASE]
        at org.springframework.boot.SpringApplication.run(SpringApplication.java:1248) ~[spring-boot-2.1.2.RELEASE.jar!/:2.1.2.RELEASE]
        at de.SWS.PLM.ProjectA.ProjectAServiceApplication.main(ProjectAServiceApplication.java:10) ~[classes!/:na]
        at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na]
        at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:na]
        at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na]
        at java.base/java.lang.reflect.Method.invoke(Method.java:566) ~[na:na]
        at org.springframework.boot.loader.MainMethodRunner.run(MainMethodRunner.java:48) ~[project-a-0.0.1-SNAPSHOT.jar:na]
        at org.springframework.boot.loader.Launcher.launch(Launcher.java:87) ~[project-a-0.0.1-SNAPSHOT.jar:na]
        at org.springframework.boot.loader.Launcher.launch(Launcher.java:50) ~[project-a-0.0.1-SNAPSHOT.jar:na]
        at org.springframework.boot.loader.JarLauncher.main(JarLauncher.java:51) ~[project-a-0.0.1-SNAPSHOT.jar:na]
Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate [de.SWS.PLM.ProjectA.service.TestService]: Constructor threw exception; nested exception is java.lang.NoClassDefFoundError: de/SWS/PLM/Commodity
        at org.springframework.beans.BeanUtils.instantiateClass(BeanUtils.java:184) ~[spring-beans-5.1.4.RELEASE.jar!/:5.1.4.RELEASE]
        at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:87) ~[spring-beans-5.1.4.RELEASE.jar!/:5.1.4.RELEASE]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateBean(AbstractAutowireCapableBeanFactory.java:1262) ~[spring-beans-5.1.4.RELEASE.jar!/:5.1.4.RELEASE]
        ... 24 common frames omitted
Caused by: java.lang.NoClassDefFoundError: de/SWS/PLM/Commodity
        at de.SWS.PLM.ProjectA.service.TestService.<init>(TestService.java:12) ~[classes!/:na]
        at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method) ~[na:na]
        at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62) ~[na:na]
        at java.base/jdk.internal.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45) ~[na:na]
        at java.base/java.lang.reflect.Constructor.newInstance(Constructor.java:490) ~[na:na]
        at org.springframework.beans.BeanUtils.instantiateClass(BeanUtils.java:172) ~[spring-beans-5.1.4.RELEASE.jar!/:5.1.4.RELEASE]
        ... 26 common frames omitted
Caused by: java.lang.ClassNotFoundException: de.SWS.PLM.Commodity
        at java.base/java.net.URLClassLoader.findClass(URLClassLoader.java:471) ~[na:na]
        at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:589) ~[na:na]
        at org.springframework.boot.loader.LaunchedURLClassLoader.loadClass(LaunchedURLClassLoader.java:93) ~[project-a-0.0.1-SNAPSHOT.jar:na]
        at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:522) ~[na:na]
        ... 32 common frames omitted

我在设置 gradle 多模块项目时做错了什么?

【问题讨论】:

  • stackoverflow.com/questions/62891554/…我在这里回答了同样的问题
  • project-b 是一个库还是一个独立项目,还是只是前者? (例如,你会运行它吗?)
  • project-b 是根项目中的独立项目模块。是的,我用 IntelJ 运行多模块项目没有错误。只有当我构建它并运行 jar 时,我才会得到 classNotFoundException

标签: spring-boot gradle multi-module


【解决方案1】:

问题在于您打包project-b 的方式。你依赖它作为一个库(因为你依赖于它来自project-a)和一个独立的可执行jar。但是您不能对这两个用例使用相同的 jar 文件。

当你应用 Spring Boot 插件时,默认情况下它会禁用正常的 jar 任务,而是生成一个捆绑了所有依赖项的“胖”jar,但也以普通 Java 程序无法再进行的方式排列在其中找到课程。要重新启用原始的jar 任务,并将胖罐重命名为同名,请执行以下操作:

jar {
    enabled = true
}

bootJar {
    classifier = 'boot'
}

执行此操作时,您将在构建时获得两个 jar 文件。一个是当你使用它作为正常依赖时,另一个是执行它。

我认为它在 IntelliJ 中工作的原因是因为您没有将任务委派给 Gradle,或者您正在通过 bootRun 运行它。这两种方法都不会构建和运行最终的可执行 jar,而只是以分解的形式使用已编译的类。

有时,更好的设计是将project-aproject-b 共有的类提取到共享实用程序项目中,而不是将整个应用程序捆绑在另一个应用程序中(有时这就是您想要的原因) .但是如果您在上面应用 Spring Boot 插件,您将需要为此进行与上述相同的配置,您可能会这样做以响应dependency-management 插件。

您可以在 Packaging Executable and Normal Archives 下的 Spring Boot Gradle 插件文档的文档中找到更多信息。

【讨论】:

  • 您好,感谢您的回复。好的,我将上面的代码插入到我的主 bu​​ild.gradle 中。现在,如果我构建项目,我会得到两个 *.jars,如你所说。我的下一步是构建 jar 的 DockerImage。但现在我有两个。此时我不知道应该使用哪一个,或者我的 docker 映像中需要两个 jar?
  • 对于 docker 镜像,您只需要名称中带有“boot”的那个。那是可执行文件。
【解决方案2】:

好的,我执行以下操作

添加

jar {
    enabled = true
}

bootJar {
    classifier = 'boot'
}

到我的项目-a。然后构建它并收到两个 *.jars。我将 boot.jar 包含到我的 dockerfile 中并进行了部署。不幸的是我得到了同样的错误

Error starting ApplicationContext. To display the conditions report re-run your application with 'debug' enabled.
22-07-2020 08:05:01.610 ERROR org.springframework.boot.SpringApplication.reportFailure - Application run failed
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'priceService': Lookup method resolution failed; nested exception is java.lang.IllegalStateException: Failed to introspect Class [de.SWS.PLM.PriceParseService.services.PriceService] from ClassLoader [org.springframework.boot.loader.LaunchedURLClassLoader@7225790e]
        at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.determineCandidateConstructors(AutowiredAnnotationBeanPostProcessor.java:265)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.determineConstructorsFromBeanPostProcessors(AbstractAutowireCapableBeanFactory.java:1236)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1151)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:538)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:498)
        at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:320)
        at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222)
        at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:318)
        at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199)
        at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:846)
        at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:863)
        at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:546)
        at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:142)
        at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:775)
        at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:397)
        at org.springframework.boot.SpringApplication.run(SpringApplication.java:316)
        at org.springframework.boot.SpringApplication.run(SpringApplication.java:1260)
        at org.springframework.boot.SpringApplication.run(SpringApplication.java:1248)
        at de.SWS.PLM.PriceParseService.PriceParseServiceApplication.main(PriceParseServiceApplication.java:17)
        at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
        at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.base/java.lang.reflect.Method.invoke(Method.java:566)
        at org.springframework.boot.loader.MainMethodRunner.run(MainMethodRunner.java:48)
        at org.springframework.boot.loader.Launcher.launch(Launcher.java:87)
        at org.springframework.boot.loader.Launcher.launch(Launcher.java:50)
        at org.springframework.boot.loader.JarLauncher.main(JarLauncher.java:51)
Caused by: java.lang.IllegalStateException: Failed to introspect Class [de.SWS.PLM.PriceParseService.services.PriceService] from ClassLoader [org.springframework.boot.loader.LaunchedURLClassLoader@7225790e]
        at org.springframework.util.ReflectionUtils.getDeclaredMethods(ReflectionUtils.java:686)
        at org.springframework.util.ReflectionUtils.doWithMethods(ReflectionUtils.java:583)
        at org.springframework.util.ReflectionUtils.doWithMethods(ReflectionUtils.java:568)
        at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.determineCandidateConstructors(AutowiredAnnotationBeanPostProcessor.java:248)
        ... 26 common frames omitted
Caused by: java.lang.NoClassDefFoundError: de/SWS/PLM/utils/ExcelCellTypeError
        at java.base/java.lang.Class.getDeclaredMethods0(Native Method)
        at java.base/java.lang.Class.privateGetDeclaredMethods(Class.java:3166)
        at java.base/java.lang.Class.getDeclaredMethods(Class.java:2309)
        at org.springframework.util.ReflectionUtils.getDeclaredMethods(ReflectionUtils.java:668)
        ... 29 common frames omitted
Caused by: java.lang.ClassNotFoundException: de.SWS.PLM.utils.ExcelCellTypeError
        at java.base/java.net.URLClassLoader.findClass(URLClassLoader.java:471)
        at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:589)
        at org.springframework.boot.loader.LaunchedURLClassLoader.loadClass(LaunchedURLClassLoader.java:93)
        at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:522)
        ... 33 common frames omitted

如果我检查 boot.jar 的结构,它看起来像

BOOT-INF
|
|---classes
|   |---package.name
|       |---project-a
|           |---all the classes without the classes of project-b
|---lib
META-INF
org

所以在两个 jar 中都没有 project-b 的类,所以 project-a 找不到我认为的类

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-02-19
    • 2019-07-02
    • 1970-01-01
    • 2020-06-26
    • 2021-03-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多