当前位置: 首页 > 知识库问答 >
问题:

打包非模块化JavaFX应用程序

赖运珧
2023-03-14

我有一个Java8应用程序,它使用JavaFX,主类扩展了JavaFX.application.application。目前,我将它作为一个fat jar交付,它在Oracle Java8上运行良好。

现在我希望它能够在OpenJDK11上运行。为了添加JavaFX,我已经将org.openjfx中的工件添加到类路径中,并将它们包含在fat JAR中。如果我从命令行启动我的jar,我会得到

Error: JavaFX runtime components are missing, and are required to run this
application
  1. 脏的一个:编写一个特殊的启动器,它不扩展应用程序并绕过模块检查。参见http://mail.openjdk.java.net/pipermail/openjfx-dev/2018-june/021977.html
  2. 干净的一个:将--module-path和--add-modules添加到我的命令行。此解决方案的问题是,我希望最终用户能够双击应用程序即可启动该应用程序

而我可以用1。作为一种解决办法,我想知道目前(OpenJDK 11)构建/交付非模块化JavaFX应用程序的可执行fat JAR的预期方法是什么。有人能帮忙吗?

共有1个答案

韦衡
2023-03-14

以下是打包/分发(非模块化)JavaFX11终端应用程序的几个选项。其中大部分在官方的OpenJFX文档中进行了解释。

我将用这个示例作为参考。我也会用Gradle。使用Maven(不同的插件)也可以完成类似的工作,甚至不使用构建工具(但不推荐使用这种方法...)。构建工具是现在必须的。

这仍然是一个有效的选择,但不是首选的选择,因为它打破了模块化设计,将所有东西捆绑在一起,而且它不是跨平台的,除非您注意到这一点。

对于给定的示例,您有一个build.gradle文件,如下所示:

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

repositories {
    mavenCentral()
}

dependencies {
}

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

mainClassName = 'hellofx.HelloFX'

jar {
    manifest {
        attributes 'Main-Class': 'hellofx.Launcher'
    }
    from {
        configurations.compile.collect { it.isDirectory() ? it : zipTree(it) }
    }
}

请注意使用launcher类。正如OP提到的或这里解释的,现在需要一个不是从application扩展的launcher类来创建fat JAR。

运行./gradlew jar将生成一个包含JavaFX类和当前平台的本机库的fat jar(~8 MB)。

您可以像往常一样运行java-jar build/libs/hellofx.jar,但只能在同一个平台中运行。

正如OpenJFX文档或本文中所解释的,您仍然可以创建跨平台JAR。

在这种情况下,我们可以包括三个图形JAR,因为它们具有依赖于平台的代码和库。基、控件和fxml模块与平台无关。

dependencies {
    compile "org.openjfx:javafx-graphics:11.0.1:win"
    compile "org.openjfx:javafx-graphics:11.0.1:linux"
    compile "org.openjfx:javafx-graphics:11.0.1:mac"
}

(注意,媒体和Web还具有与平台相关代码/本机库)。

因此,这与以前在Java8上一样工作。但正如我之前所说的,它打破了模块的工作方式,也不符合当前库和应用程序的分布方式。

并且不要忘记,这些JAR的用户仍然必须安装一个JRE。

有了这个建筑.Gradle:

plugins {
    id 'org.openjfx.javafxplugin' version '0.0.5'
    id 'org.beryx.runtime' version '1.0.0'
    id "com.github.johnrengelman.shadow" version "4.0.3"
}

repositories {
    mavenCentral()
}

dependencies {
}

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

mainClassName = 'hellofx.Launcher'

runtime {
    options = ['--strip-debug', '--compress', '2', '--no-header-files', '--no-man-pages']
}

当您运行./gradlew runtime时,它将创建一个运行时及其启动程序,因此您可以运行:

cd build/image/hellofx/bin
./hellofx

注意它依赖于shadow插件,并且它还需要一个Launcher类。

有关为其他平台构建映像,请参阅targetplatform

我们一直认为我们有一个非模块化的项目,这是不能改变的...但如果我们真的改变了呢?

模块化并不是一个很大的改变:您添加了module-info.java描述符,并且在其上包含了所需的模块,即使这些是非模块化的JAR(基于自动名称)。

基于相同的示例,我将添加一个描述符:

module hellofx {
    requires javafx.controls;

    exports hellofx;
}

现在我可以在命令行上使用jlink或使用插件。badass-gradle-plugin是一个gradle plugin,与前面提到的作者相同,它允许创建定义运行时。

使用此生成文件:

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

repositories {
    mavenCentral()
}

dependencies {
}

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

mainClassName = 'hellofx/hellofx.HelloFX'
./gradlew jlink
cd build/image/bin/hellofx
./hellofx

最后,有一个新的工具来创建可执行安装程序,您可以使用这些安装程序来分发应用程序。

到目前为止还没有GA版本(我们可能要等到Java13),但是现在有两种选择可以将它与Java11或12一起使用:

对于Java/JavaFX11,在Java12上的JPackager的初始工作中有一个后端口,您可以在这里找到。这里有一篇关于使用它的很好的文章,这里有一个使用它的gradle项目。

这是该工具的一个非常初步的使用:

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

repositories {
    html" target="_blank">mavenCentral()
}

dependencies {
}

javafx {
    version = "12-ea+5"
    modules = [ 'javafx.controls' ]
}

mainClassName = 'hellofx/hellofx.HelloFX'

def java_home = '/Users/<user>/Downloads/jdk-12.jdk/Contents/Home'
def installer = 'build/installer'
def appName = 'HelloFXApp'

task copyDependencies(type: Copy) {
    dependsOn 'build'
    from configurations.runtime
    into "${buildDir}/libs"
}

task jpackage(type: Exec) {
    dependsOn 'clean'
    dependsOn 'copyDependencies'

    commandLine "${java_home}/bin/jpackage", 'create-installer', "dmg",
            '--output', "${installer}", "--name", "${appName}",
            '--verbose', '--echo-mode', '--module-path', 'build/libs',
            '--add-modules', "${moduleName}", '--input', 'builds/libraries',
            '--class', "${mainClassName}", '--module', "${mainClassName}"
}

现在运行./gradlew jpackage将生成一个dmg(65 MB),我可以将其分发安装:

虽然您可以坚持使用经典的fat JAR,但当转移到Java11和更高版本时,一切都应该是模块化的。新的(即将推出的)可用工具和插件,包括IDE支持,在这一过渡过程中起到了帮助作用。

我知道我在这里展示了最简单的用例,当尝试更复杂的实际用例时,会有几个问题...但是,我们应该更好地努力解决这些问题,而不是继续使用过时的解决办法。

 类似资料:
  • 我的模块化JavaFX应用程序有问题。我创建了一个JavaFX项目,并添加了JavaFX库和JavaFX模块。但是,我不断收到以下错误消息: 完整设置的图像附于此: 编辑: 以下是所有错误消息: 我还添加了vm选项: 但是,我还是收到了这个错误消息。

  • 我开发并发布了一个使用Apache Batik和JavaCV的Java Swing应用程序。我已经通过java 1.6、7和8对其进行了更新。macOS、Windows和Linux的安装程序是使用Javapackager构建的。Java 8将于1月19日停止支持,我找不到一个解决方案来打包和分发新的LTS版本Java 11。 JavaCV和Batik都不生产模块化jar,但我已经成功地对它们进行了

  • 为缓解 Windows 下路径名过长的 问题, 略微加快一下 require的速度以及隐藏你的源代码,你可以选择把你的应用打包成 asar档案文件,这只需要对你的源代码做一些很小的改动。 大部分用户可以毫不费力地使用这个功能,因为它electron-packager,、electron-forge和electron-builder中都得到了支持,开箱即用。 如果你没有使用这些工具中的任何一个,那么

  • 我的目标是使用JLink将应用程序打包成与自定义JRE捆绑在一起的模块化运行时映像。我的应用程序是一个简单的“Hello World”Java标准版应用程序,依赖于番石榴。我使用JDK11。 基本上,我试图复制Baeldung的教程,但使用NetBeans,Maven管理依赖关系,并使用Maven编译器插件版本3.8.1构建模块系统。 目录结构:

  • 为了完整起见,我使用Oracle JDK 1.8.0_66 for Mac。

  • 问题内容: 我一直在寻找创建模块化Web应用程序的解决方案,该模块是模块化的,即用户可以以简单jar的形式提供自己的插件,然后将其自身的数据提供给我的Web应用程序,而我的webapp将负责用于显示它。 现在的问题是,我希望我的Web应用程序尽可能通用,而不依赖于j2ee Web容器来支持任何内容。即,我不能依靠我的Web容器来提供osgi支持并将Web应用程序作为osgi捆绑包本身部署(这确实使