使用Gradle向运行时映像添加依赖项
我不知道如何添加依赖项.我的模块需要Log4j.我在模块信息中添加了要求.我还添加了gradle依赖项.我可以运行项目,但不能创建自定义运行时映像.
I don't know how to add dependency. My module needs Log4j. I added requirement to module info. I added also to gradle dependencies. I can run project, but I can't create custom runtime image.
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'
}
当我执行任务链接时,我得到:
When I fire task jlink I get:
错误:未找到模块org.apache.logging.log4j,由 应用
Error: Module org.apache.logging.log4j not found, required by app
我检查了build中的libs目录,但没有log4j jar.如何告诉gradle为jlink任务添加依赖项?
I checked libs directory in build and there is not log4j jar. How to tell gradle to add dependencies to jlink task?
问题
这是您在jlink
任务中所拥有的:
This is what you have in your jlink
task:
'--module-path', "libs${File.pathSeparatorChar}${fx_jmods}"
这意味着您要添加以下项的依赖关系:
Whats means that you are adding the dependencies from:
-
libs
:基本上是模块helloFX
的jar.这是jar
任务的结果,该任务仅包括项目的类和资源,但不包括其依赖项.
libs
: basically the jar of your modulehelloFX
. This is a result of thejar
task, that only includes the classes and resources of your project, but not its dependencies.
fx_jmods
:这是JavaFX jmods的路径.
fx_jmods
: That is the path to the JavaFX jmods.
但是当您运行时,会出现此错误:
But when you run, you get this error:
错误:应用程序未找到模块org.apache.logging.log4j
Error: Module org.apache.logging.log4j not found, required by app
该错误表示jlink
命令的module-path
未完成,并且无法解析所有必需的依赖项.如上所述,我们仅包含module.jar和JavaFX(jmods)jar,但不包括log4j.jar
.
The error means that the module-path
for the jlink
command is not complete, and it can't resolve all the required dependencies. As mentioned above, we are only including the module.jar and the JavaFX (jmods) jars, but not the log4j.jar
.
因此,我们需要找到一种方法来将该jar添加到模块路径中.
So we need to find a way to add that jar to the module-path.
有几种可能的解决方案,可以在您的自定义映像中包含第三方依赖项.
There are a few possible solutions to include third party dependencies in your custom image.
解决方案1
我们必须修改jlink
任务,以在我们的运行时配置中包括现有的依赖项.
We have to modify the jlink
task, to include the existing dependencies in our runtime configuration.
最直接的解决方案是在本地.gradle存储库中找到gradle将logj4 jar存储在何处.
The most immediate solution is finding where the logj4 jars are stored by gradle, in the local .gradle repository.
'--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"
虽然此解决方案有效,但它并不是最方便的,因为它取决于来自用户的本地路径.
While this solution works, it is not the most convenient, of course, as it depends on local paths from the user.
解决方案2
可以添加一个任务,将通过gradle直接解决的运行时依赖项复制到libs
文件夹中,这是一个更好的解决方案,例如:
A better solution, can be done adding a task to copy the runtime dependencies, that are resolved directly by gradle, into the libs
folder like:
task libs(type: Copy) {
into 'build/libs/'
from configurations.runtime
}
,然后从jlink
任务调用此任务:
and then calling this task from the jlink
task:
task jlink(type: Exec) {
dependsOn 'clean'
dependsOn 'jar'
dependsOn 'libs'
...
}
如果运行./gradlew jlink
并检查libs
文件夹,则应该找到类似以下内容的文件:
If you run ./gradlew jlink
and check the libs
folder you should find something like this:
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
是您正在运行的平台.
where $platform
is your running platform.
请注意,libs
文件夹现在包含模块路径所需的 all 依赖项,并且JavaFX-*-$ platform jars 包含因此,在本机库中,不再需要在module-path选项中使用jmods.这样就足够了:
Notice that the libs
folder now contains all the dependencies that are required for the module path, and also that the JavaFX-*-$platform jars contain the native libraries, therefore, the jmods are not needed anymore in the module-path option. This will be enough:
'--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
任务.
You can run your jlink
task now successfully.
解决方案3
如@madhead注释所建议,您可以将另一个插件用于jlink
任务:所谓的
As suggested by @madhead comment, you can use another plugin for the jlink
task: the so called 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'
}
}
Note also that the plugin has an option to create image for other platforms (see targetPlatform).
编辑log4j
如注释中所述,log4j
依赖项还不适用于模块.在Apache上有一个公开问题问题追踪器:
As mentioned in the comments, the log4j
dependency doesn't play well with modules yet. There is an open issue at the Apache Issue tracker:
当前基于给定的自动模块,您不能在要使用jlink生成运行时映像的项目中使用log4j-core.
Currently based on the given automatic modules you can't use log4j-core in a project where you like to use jlink to produce a runtime image.
我已将其添加到我的主班:
I've added this to my main class:
LogManager.getLogger(MainApp.class).info("hellofx!");
,并且我已将log4j2.xml
文件添加到src/main/resources
.
and I've added the log4j2.xml
file to src/main/resources
.
运行./gradlew run
,有效:
> Task :run
18:24:26.362 [JavaFX Application Thread] INFO eu.sample.app.Main - hellofx!
但是,从解决方案2运行jlink会创建自定义图像,我可以验证是否包含了xml文件,但是从该图像运行时,我得到了:
But, running jlink from Solution 2, creates the custom image, I can verify that the xml file is included, but when running from the image I get:
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...
并且如上所述,在createMergedModule
任务中,使用解决方案3的插件运行jlink失败:
And as mentioned, running jlink with the plugin from Solution 3 fails at the :createMergedModule
task
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;
[请参阅EDIT(2),此问题自版本2.1.9起已得到修复]
[See EDIT(2), this has been fixed since version 2.1.9]
替代
在这一点上,可能的替代方法是改用Slf4j.成功使用插件的文档中列出了一个示例.
At this point, a possible alternative could be use Slf4j instead. There is a sample listed from the plugin documentation that uses it successfully.
总之,这是必需的:
成绩文件:
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
"rel =" nofollow noreferrer">这里和logback.xml
来自这里,与您的主要班级一起.
logging.properties
from here and logback.xml
from here, with your main class.
同时运行./gradlew
run或./gradlew jlink
,并且build/image/bin/HelloFX
正常运行,并且消息记录到控制台.
Both running ./gradlew
run or ./gradlew jlink
, and build/image/bin/HelloFX
work, and the message is logged to the console.
编辑(2)
在报告问题后,将问题提交给badass-jlink-plugin问题追踪器,此问题已解决,并且从2.1.19版本开始,它应该可以很好地创建自定义图像.
After reporting the issue to the badass-jlink-plugin's issue tracker, this was solved, and since version 2.1.19 it should work fine creating a custom image.
由于log4j
是多版本jar,因此需要做一件事:
Since log4j
is multi-release jar, there is one thing required:
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
}
在此处中查看完整的工作示例..
See a full working sample here.