简体   繁体   English

带有测试 Spring Boot 的 Gradle fat jar 的 NoClassDefFoundError

[英]NoClassDefFoundError for Gradle fat jar with tests Spring Boot

I need to create fat jar in Gradle project with tests where Main method is under src/test.我需要在 Gradle 项目中创建带有测试的胖 jar,其中 Main 方法位于 src/test 下。 Now I have Exception in thread "main" java.lang.NoClassDefFoundError: org/apache/commons/cli/CommandLineParser when I run fat jar created by 'gradle bootJar'.现在,当我运行由“gradle bootJar”创建的胖 jar 时Exception in thread "main" java.lang.NoClassDefFoundError: org/apache/commons/cli/CommandLineParser中出现异常。

My Gradle:我的摇篮:

plugins {
    id 'org.springframework.boot' version '2.1.7.RELEASE'
}

apply plugin: 'io.spring.dependency-management'

dependencies {
    compile group: 'org.springframework', name: 'spring-context', version: '5.1.9.RELEASE'
    compile group: 'org.springframework', name: 'spring-web', version: '5.1.9.RELEASE'
    compile group: 'org.springframework', name: 'spring-aop', version: '5.1.9.RELEASE'
    compile group: 'org.springframework', name: 'spring-aspects', version: '5.1.9.RELEASE'
    compile group: 'org.springframework', name: 'spring-test', version: '5.0.5.RELEASE'

    compile group: 'commons-cli', name: 'commons-cli', version: '1.4'
}

bootJar {
    manifest {
        attributes 'Start-Class': 'com.company.MainRunner'
    }
    from sourceSets.test.output.classesDirs
}

My spring.xml:我的spring.xml:

<?xml version="1.0" encoding="UTF-8"?>
<beans default-lazy-init="true" xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
                           http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
                           http://www.springframework.org/schema/context
                           http://www.springframework.org/schema/context/spring-context-4.3.xsd
                           http://www.springframework.org/schema/aop
                           http://www.springframework.org/schema/aop/spring-aop-4.3.xsd">

    <aop:aspectj-autoproxy/>

<bean> ... </bean>
<bean> ... </bean>

</beans>

Exception:例外:

Exception in thread "main" java.lang.NoClassDefFoundError: org/apache/commons/cli/CommandLineParser

Previously following 'gradle shadowJar' code worked well until I added AspectJ to the project以前遵循“gradle shadowJar”代码运行良好,直到我将 AspectJ 添加到项目中

buildscript {
    repositories {
        jcenter()
        mavenCentral()
    }
    dependencies {
        classpath 'com.github.jengelman.gradle.plugins:shadow:4.0.3'
    }
}

apply plugin: 'com.github.johnrengelman.shadow'

shadowJar {
    manifest {
        attributes 'Main-Class': 'com.company.MainRunner'
    }
    from sourceSets.test.output.classesDirs

    configurations = [project.configurations.testRuntime]
}

And error appeared on running 'gradle shadowJar'运行“gradle shadowJar”时出现错误

Unable to locate Spring NamespaceHandler for XML schema namespace [http://www.springframework.org/schema/aop]

Somewhere I found that shadowJar doesn't work properly with Spring在某个地方我发现 shadowJar 不能与 Spring 一起正常工作

How can I create fat jar for Spring project with main class under src/test?如何在 src/test 下使用主类为 Spring 项目创建胖 jar?

This Gradle shadowJar works for me这个 Gradle shadowJar 对我有用

import com.github.jengelman.gradle.plugins.shadow.transformers.AppendingTransformer

shadowJar {
    mergeServiceFiles()
    transform(AppendingTransformer) { resource = 'META-INF/spring.handlers' }
    transform(AppendingTransformer) { resource = 'META-INF/spring.schemas' }

    manifest {
        attributes 'Main-Class': 'com.company.MainRunner'
    }
    from sourceSets.test.output.classesDirs

    configurations = [project.configurations.testRuntime]
}

Exception in thread "main" java.lang.NoClassDefFoundError: org/apache/commons/cli/CommandLineParser线程“主”java.lang.NoClassDefFoundError 中的异常:org/apache/commons/cli/CommandLineParser

According to the above error, it seems like you have a missing library ( Apache Commons-CLI ) in your classpath.根据上述错误,您的类路径中似乎缺少库( Apache Commons-CLI )。 So add that library and try again.因此,添加该库并重试。

And about this error,关于这个错误,

Unable to locate Spring NamespaceHandler for XML schema namespace [ http://www.springframework.org/schema/aop]无法找到 XML 模式命名空间的 Spring NamespaceHandler [ http://www.springframework.org/schema/aop]

The problem occurs when using the aop namespace without having the necessary aop spring library on the classpath.使用aop命名空间而类路径上没有必要的aop spring 库时会出现问题。

But I see you have imported that library.但我看到你已经导入了那个库。

Another cause is you are trying to create a fat.jar file, so spring.handlers / spring.schemas get overwritten when merging multiple spring dependencies into a single jar file.另一个原因是您正在尝试创建一个 fat.jar 文件,因此当将多个 spring 依赖项合并到一个 jar 文件中时, spring.handlers / spring.schemas会被覆盖。

So I suggest to use Apache Maven Shade Plugin and rebuild the project.所以我建议使用Apache Maven Shade Plugin并重建项目。 And this is the Gradle version of Apache Maven's Shade Plugin .这是Apache Maven 的 Shade Plugin的 Gradle 版本。

The Shadow Plugin for gradle has a problem: You have to tell it how to handle file collisions, ie files with the same name. gradle的Shadow Plugin有一个问题:你必须告诉它如何处理文件冲突,即同名文件。 While this is not hard, like @Roman Harasymenko mentioned and I use it (Kotlin DSL):虽然这并不难,就像@Roman Harasymenko 提到的那样,我使用它(Kotlin DSL):


tasks.withType<ShadowJar> {
    mergeServiceFiles()
    append("META-INF/spring.handlers")
    append("META-INF/spring.schemas")
    append("META-INF/spring.tooling")
    transform(
        PropertiesFileTransformer().apply {
            paths = mutableListOf("META-INF/spring.factories")
            mergeStrategy = "append"
        })
}

it doesn't tell in its current version when such a conflict occurs, so you have to waste big amounts of time finding the conflicts yourself.它不会在当前版本中说明何时发生此类冲突,因此您必须浪费大量时间自己查找冲突。 But there is a pull request that it tells if there is a collision: https://github.com/johnrengelman/shadow/pull/773 .但是有一个拉取请求,它告诉它是否存在冲突: https ://github.com/johnrengelman/shadow/pull/773。 Until the pull request gets merged you could use the forked branch to be always informed about file collisions: https://github.com/JD-CSTx/shadow/tree/chapmajs-collision_logging在合并拉取请求之前,您可以使用分叉分支始终了解文件冲突: https ://github.com/JD-CSTx/shadow/tree/chapmajs-collision_logging

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM