Как добавить classpath в задачу Gradle JavaExec, чтобы выполнить исполняемый файл jar? - PullRequest
2 голосов
/ 20 апреля 2019

Мое приложение требует spring-context библиотеки. Итак, в моем файле build.gradle я добавляю эту зависимость,

dependencies {
    compile 'org.springframework:spring-context:5.1.6.RELEASE'
}

Я также хочу создать исполняемый файл JAR, задача jar выглядит так,

jar {
    manifest {
        attributes 'Main-Class': 'my.package.my.main.class'
    }
}

Когда я запустил файл сборки, все в порядке,

gradle build

Но когда я попытался запустить это работоспособное jar-приложение,

task runJar(dependsOn: jar, type: JavaExec) {
    classpath(configurations.compile)
    main = '-jar'; args 'build/libs/my-runnable.jar'
}

Консоль брошенная NoClassDefFoundError,

Exception in thread "main" java.lang.NoClassDefFoundError: 
org/springframework/context/ConfigurableApplicationContext
...
...

Я пробовал sourceSets.main.runtimeClasspath, проблема осталась прежней,

task runJar(dependsOn: jar, type: JavaExec) {
    classpath(sourceSets.main.runtimeClasspath)
    main = '-jar'; args 'build/libs/my-runnable.jar'
}

Я проверил коллекцию файлов classpath,

classpath.each {
    println it.name
}

spring-context пакет был прямо там,

spring-context-5.1.6.RELEASE.jar
spring-aop-5.1.6.RELEASE.jar
spring-beans-5.1.6.RELEASE.jar
spring-expression-5.1.6.RELEASE.jar
spring-core-5.1.6.RELEASE.jar
spring-jcl-5.1.6.RELEASE.jar

Тогда я попробовал другой подход, чтобы решить эту проблему. Я извлек все файлы классов из этих .jar библиотек и включил их непосредственно в мои окончательные runnable.jar,

jar {
    manifest {
        attributes 'Main-Class': 'my.package.my.main.class'
    }

    configurations.compile.each {
        from(project.zipTree(it))
    }
}

И это решение работает. Но такая «толстая банка» - не то, что я хочу.

Я новичок в Gradle. Это действительно смутило меня. Кто-нибудь может помочь? Спасибо!

1 Ответ

0 голосов
/ 21 апреля 2019

После примерно 3 часов работы простая истина такова:

Если вы укажете -jar, параметр -cp будет игнорироваться.

Некоторое подробное обсуждение находится в этом вопросе:

Запустите файл JAR из командной строки и укажите classpath

Есть 2 простых шагарешения:

  1. Извлеките все файлы .class непосредственно в исполняемый файл, как я уже упоминал в своем вопросе.
jar {
    manifest {
        attributes 'Main-Class': 'my.package.my.main.class'
    }

    configurations.compile.each {
        from(project.zipTree(it))
    }
}
Вторым решением является добавление параметров Class-Path в файл manifest.
jar {
    manifest {
        attributes 'Main-Class': 'your.main.class.full.name'
        attributes 'Class-Path': configurations.compile.collect { it.name }.join(' ')
    }
}

Убедитесь, что вы можете найти библиотеки .jar в вашей локальной системе.Например, просто скопируйте их в один и тот же каталог,

task copyLibs(type: Copy) {
    from configurations.compile
    into 'build/libs/'
}

После этого мой каталог build/libs/ будет выглядеть так:

build
├── libs
│   ├── my-runnable-app.jar
│   ├── spring-aop-5.1.6.RELEASE.jar
│   ├── spring-beans-5.1.6.RELEASE.jar
│   ├── spring-context-5.1.6.RELEASE.jar
│   ├── spring-core-5.1.6.RELEASE.jar
│   ├── spring-expression-5.1.6.RELEASE.jar
│   └── spring-jcl-5.1.6.RELEASE.jar

Обратите внимание, что все библиотеки .jar расположены вне my-runnable-app.jar.Если вы хотите включить их в свой my-runnable-app.jar, вам нужен One-Jar инструментарий.Для получения дополнительной информации о One-Jar, пожалуйста, прочитайте этот вопрос:

Эталонные банки внутри банки

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...