Задача
Это то, что у вас есть в вашей 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
}
Смотрите полный рабочий образец здесь .