Добавьте зависимости в образ времени выполнения с помощью Gradle - PullRequest
0 голосов
/ 13 декабря 2018

Я не знаю, как добавить зависимость.Моему модулю нужен Log4j.Я добавил требование к информации модуля.Я добавил также к Gradle зависимости.Я могу запустить проект, но не могу создать собственный образ времени выполнения.

plugins {
    id 'java'
    id 'application'
    id 'org.openjfx.javafxplugin' version '0.0.5'
}

group 'eu.sample'
version '2.0'


repositories {
    mavenCentral()
}

javafx {
    modules = [ 'javafx.controls', 'javafx.fxml' ]
}

mainClassName = "$moduleName/eu.sample.app.Main"

def lin_java_home = hasProperty('org.gradle.java.home') ? getProperty('org.gradle.java.home') : System.getenv('JAVA_HOME')
def lin_fx_jmods = hasProperty('linux.fx.mods') ? getProperty('linux.fx.mods') : System.getenv('PATH_TO_FX_MODS_LIN')

def win_java_home = hasProperty('windows.java.home') ? getProperty('windows.java.home') : System.getenv('JAVA_HOME_WIN')
def win_fx_jmods = hasProperty('windows.fx.mods') ? getProperty('windows.fx.mods') : System.getenv('PATH_TO_FX_MODS_WIN')

dependencies {
    compile group: 'org.apache.logging.log4j', name: 'log4j-core', version: '2.11.1'
}

task jlink(type: Exec) {
    dependsOn 'clean'
    dependsOn 'jar'

    workingDir 'build'

    if (lin_java_home == null) {
        throw new RuntimeException("java_home is not defined.")
    }
    if (lin_fx_jmods == null) {
        throw new RuntimeException("fx_jmods is not defined.")
    }
    commandLine "${lin_java_home}/bin/jlink", '--module-path', "libs${File.pathSeparatorChar}${lin_fx_jmods}",
            '--add-modules', "${moduleName}", '--output', "${moduleName}", '--strip-debug',
            '--compress', '2', '--no-header-files', '--no-man-pages'
}

task jlinkWin(type: Exec) {
    dependsOn 'clean'
    dependsOn 'jar'


    workingDir 'build'

    if (win_java_home == null) {
        throw new RuntimeException("java_home is not defined.")
    }
    if (win_fx_jmods == null) {
        throw new RuntimeException("fx_jmods is not defined.")
    }
    commandLine "${lin_java_home}/bin/jlink", '--module-path', 
            "${win_java_home}/jmods${File.pathSeparatorChar}libs${File.pathSeparatorChar}${win_fx_jmods}",
            '--add-modules', "${moduleName}", '--output', "${moduleName}", '--strip-debug',
            '--compress', '2', '--no-header-files', '--no-man-pages'
}

Когда я запускаю задачу jlink, я получаю:

Ошибка: модуль org.apache.logging.log4j не найден, требуется приложению

Я проверил каталог libs в сборке и там нет jar log4j.Как сказать gradle добавить зависимости в задачу jlink?

1 Ответ

0 голосов
/ 13 декабря 2018

Задача

Это то, что у вас есть в вашей jlink задаче:

'--module-path', "libs${File.pathSeparatorChar}${fx_jmods}"

Что означает, что вы добавляете зависимости от:

  • libs: в основном банка вашего модуля helloFX.Это результат задачи jar, которая включает только классы и ресурсы вашего проекта, но не его зависимости.

  • fx_jmods: это путь к JavaFXjmods.

Но при запуске вы получаете эту ошибку:

Ошибка: модуль org.apache.logging.log4j не найден, требуется приложению

Ошибка означает, что module-path для команды jlink не завершена, и она не может разрешить все необходимые зависимости.Как упомянуто выше, мы включаем только jar module.jar и javasf (jmods), но не log4j.jar.

Так что нам нужно найти способ добавить этот jar в путь к модулю.

Существует несколько возможных решений для включения сторонних зависимостей в ваш пользовательский образ.

Решение 1

Мы должны изменить jlinkзадача, чтобы включить существующие зависимости в нашу конфигурацию времени выполнения.

Самое непосредственное решение - найти, где jar-файлы logj4 хранятся gradle, в локальном репозитории .gradle.

'--module-path', "libs${File.pathSeparatorChar}${fx_jmods}: \
   /Users/<user>/.gradle/caches/modules-2/files-2.1/org.apache.logging.log4j/log4j-api/2.11.1/268..a10/log4j-api-2.11.1.jar: \
   /Users/<user>/.gradle/caches/modules-2/files-2.1/org.apache.logging.log4j/log4j-core/2.11.1/59..e4/log4j-core-2.11.1.jar"

Хотяэто решение работает, оно, конечно, не самое удобное, поскольку оно зависит от локальных путей пользователя.

Решение 2

Лучшим решением может бытьзавершено добавление задачи для копирования зависимостей времени выполнения, которые разрешаются непосредственно gradle, в папку libs, например:

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

, а затем вызов этой задачи из задачи jlink:

task jlink(type: Exec) {
    dependsOn 'clean'
    dependsOn 'jar'
    dependsOn 'libs'
    ...
}

Если запустить ./gradlew jlink и проверитьВ папке libs вы должны найти что-то вроде этого:

build/libs/hellofx.jar
build/libs/javafx-base-11.0.1.jar
build/libs/javafx-base-11.0.1-$platform.jar
build/libs/javafx-graphics-11.0.1.jar
build/libs/javafx-graphics-11.0.1-$platform.jar
build/libs/javafx-controls-11.0.1.jar
build/libs/javafx-controls-11.0.1-$platform.jar
build/libs/javafx-fxml-11.0.1.jar
build/libs/javafx-fxml-11.0.1-$platform.jar
build/libs/log4j-api-2.11.1.jar
build/libs/log4j-core-2.11.1.jar

, где $platform - ваша работающая платформа.

Обратите внимание, что папка libs теперь содержит all зависимости, которые требуются для пути к модулю, а также то, что jar платформы JavaFX - * - $ содержат собственных библиотек, поэтому jmod больше не нужны в опции module-path.Этого будет достаточно:

'--module-path', "libs"

, поэтому ваша командная строка будет иметь следующий вид:

commandLine "${java_home}/bin/jlink", '--module-path', "libs",
        '--add-modules', "${moduleName}", '--output', "${moduleName}", '--strip-debug', '--compress', '2', '--no-header-files', '--no-man-pages'

Теперь вы можете успешно выполнить задачу jlink.

Решение 3

Как следует из комментария @madhead, вы можете использовать другой плагин для задачи jlink: так называемый badass-jlink-plugin .

Измените свою сборку на что-то вроде:

plugins {
    id 'application'
    id 'org.openjfx.javafxplugin' version '0.0.5'
    id 'org.beryx.jlink' version '2.1.8'
}

repositories {
    mavenCentral()
}

dependencies {
    compile group: 'org.apache.logging.log4j', name: 'log4j-core', version: '2.11.1'
}

javafx {
    modules = ['javafx.controls', 'javafx.fxml']
}

mainClassName = "${moduleName}/eu.sample.app.Main"

jlink {
    options = ['--strip-debug', '--compress', '2', '--no-header-files', '--no-man-pages']
    launcher {
        name = 'helloFX'
    }
}

Также обратите внимание, что плагин имеет возможность создавать образ для других платформ (см. targetPlatform ).

РЕДАКТИРОВАТЬ о log4j

Как уже упоминалось в комментариях, зависимость log4j плохо работает с модулями.Существует открытый выпуск в трекере проблем Apache:

В настоящее время на основе данных автоматических модулей вы не можете использовать log4j-core в проекте, где вам нравится использовать jlinkдля создания образа во время выполнения.

Я добавил это в свой основной класс:

LogManager.getLogger(MainApp.class).info("hellofx!");

и добавил файл log4j2.xml в src/main/resources.

Запуск ./gradlew run, работает:

> Task :run
18:24:26.362 [JavaFX Application Thread] INFO  eu.sample.app.Main - hellofx!

Но, запустив jlink из Solution 2, создает пользовательский образ, я могу убедиться, что файл xml включен, но при запуске из образаЯ получаю:

build/hellofx/bin/java -m hellofx/eu.sample.app.Main
ERROR StatusLogger Log4j2 could not find a logging implementation. \
    Please add log4j-core to the classpath. Using SimpleLogger to log to the console...

И, как уже упоминалось, запуск jlink с плагином из решения 3 завершается неудачей при выполнении задачи createMergedModule :

 error: package org.apache.logging.log4j.spi is not visible
   provides org.apache.logging.log4j.spi.Provider with org.apache.logging.log4j.core.impl.Log4jProvider;

[см. ПРАВКА(2), это было исправлено начиная с версии 2.1.9]

Альтернатива

На этом этапе возможной альтернативой может быть использование вместо этого Slf4j.Существует образец , перечисленный в документации к плагину, который успешно его использует.

В итоге требуется:

Файл Gradle:

dependencies {
    compile 'org.slf4j:slf4j-api:1.8.0-beta2'
    compile('ch.qos.logback:logback-classic:1.3.0-alpha4') {
        exclude module: "activation"
    }
}

Информация о модуле:

requires org.slf4j;
requires ch.qos.logback.classic;
requires java.naming;

Основной класс:

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

private static final Logger logger = LoggerFactory.getLogger(MainApp.class);

...
logger.info("hellofx!");

logging.properties с здесь и logback.xml с здесь , с вашим основным классом.

Оба запускаются ./gradlew run или ./gradlew jlink, и build/image/bin/HelloFX работают, и сообщение заносится в консоль.

EDIT (2)

После сообщения о проблеме в систему отслеживания проблем badass-jlink-plugin это было решено, и начиная с версии 2.1.19 оно должно работать нормально при создании пользовательского образа.

Начиная с log4jэто мульти-релиз баночка, требуется одна вещь:

plugins {
    id 'application'
    id 'org.openjfx.javafxplugin' version '0.0.5'
    id 'org.beryx.jlink' version '2.1.9'
}

...

jlink {
    options = ['--strip-debug', '--compress', '2', '--no-header-files', '--no-man-pages']
    launcher {
       name = 'helloFX'
    }
    forceMerge('log4j-api')     // <---- this is required for Log4j
}

Смотрите полный рабочий образец здесь .

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