内容简介:使用Java 9的模块化来构建零依赖的原生应用
原文: Using Java 9 Modularization to Ship Zero-Dependency Native Apps
作者:Steve Perkins
翻译:雁惊寒
摘要:本文通过实例介绍了如果通过 Java 9的模块化特性来构建一个独立的、零依赖的可执行程序。以下是译文。
“ 为什么没办法创建一个.EXE程序? ”
在Java刚刚出现的时候,主流的编程语言要么可以编译为独立的可执行文件(例如C/C++、COBOL),要么运行在解释器中(例如 Perl 、Tcl)。对于大部分的 程序员 来说,Java对字节码编译器 和 运行时解释器的需求让他们开始转变自己的思维。编译模型使得Java比“脚本”语言更适合于业务编程。然而,运行时模型则需要在每台目标机器上部署和使用合适的JVM。
人们对此有些抵触。在早期的网络论坛,以及后来的StackOverflow问题中,为了避免在目标机器上安装Java运行时,开发者们都在寻找某种能将Java应用程序发布为“原生”可执行文件的方法。
解决办法从一开始就有。 Excelsior JET 是一个超前的Java编译器,提供了部分C++风格的体验。然而,它的许可费用高达数千美元。当然,也有免费工具,例如 Launch4j 和JDK 8的 javapackager 工具。这些 工具 能帮你把Java运行时环境与启动程序捆绑在一起,以使用该JRE来启动应用程序。但是,嵌入JRE会使应用程序增加大约200MB。由于技术上的原因以及许可问题,应用程序的大小很难降下来。
Java 9来了
Java 9中最广为人知的新功能是新的模块化系统,称为 Jigsaw项目 。简而言之,这个新模块用于隔离代码块及其依赖关系。
这个模块不仅适用于外部库,也适用于Java标准库本身。这意味着应用程序可以声明自己需要标准库的哪些部分,并 排除所有其他的部分 。
这个功能是通过 随JDK一同提供的
jlink
工具来实现的。乍一看, jlink
类似于 javapackager
。它会生成一个包,包括:
- 应用程序代码及其依赖关系;
- 一个嵌入式Java运行时环境;
- 本地启动器(例如,bash脚本或Windows批处理文件),用于通过嵌入式JRE启动应用程序。
jlink
建立了“链接时”这个新的可选阶段,它处于编译时和运行时之间,用于执行优化,例如删除不可达的代码。与捆绑整个标准库的 javapackager
不同, jlink
把精简过的JRE和仅包含应用程序所需的那些模块捆绑在一起。
示例
jlink
和老版本的 javapackager
之间的区别非常的大。为了说明这一点,我们来看一个示例项目:
https://github.com/steve-perkins/jlink-demo
(1)创建一个模块化的项目
这个代码库包含一个多项目的Gradle构建。 cli
子目录中是一个“Hello World”命令行程序,而 gui
是一个JavaFX桌面应用程序。请注意,对于这两者,通过在 build.gradle
文件中配置下面这一句来让每个项目与Java 9兼容:
sourceCompatibility = 1.9
下面将创建 module-info.java
文件,为每个项目设置模块化。
/cli/src/main/java/module-info.java :
module cli { }
/gui/src/main/java/module-info.java :
module gui { requires javafx.graphics; requires javafx.controls; exports gui; }
这里的CLI应用程序只是对 System.out.println()
的调用,所以它只依赖于 java.base
模块(这是隐式的,不需要声明)。
但并不是所有的应用程序都使用JavaFX,所以这里的GUI应用程序必须声明它对 javafx.graphics
和 javafx.controls
模块的依赖。而且,由于JavaFX的工作方式不太一样,所以底层库需要访问我们的代码。 export gui
这一行赋予了这个库的可见性。
Java开发人员(包括我自己)需要一些时间来感悟新的标准库模块以及它们包含的内容。 JDK包含的
jdeps
工具
可以帮忙用来解决这个问题。而且只要某个项目被设置为模块化,IntelliJ就能识别出丢失的声明并协助开发人员自动完成它们。即使Eclipse和NetBeans没有类似的支持,它们很快也会添加进去的。
(2)构建一个可执行的JAR
要使用 jlink
构建一个可部署的包,首先要将应用程序打包成一个可执行的JAR文件。如果项目依赖第三方库,那么需要使用“shaded”或“fat-JAR”插件来生成包含所有依赖关系的单个JAR。我们这个例子只使用了标准库,所以构建一个可执行的JAR是一件非常简单的事情,只需让Gradle的 jar
插件包含一个声明可执行类的 META-INF/MANIFEST.MF
文件:
jar { manifest { attributes'Main-Class': 'cli.Main' } }
(3)运行jlink
据我所知,Gradle还没有一个插件能够提供干净并且可以无缝集成的 jlink
。所以,我的构建脚本使用 Exec
任务来运行该工具。命令行调用是这样的:
[JAVA_HOME]/bin/jlink --module-path libs:[JAVA_HOME]/jmods --add-modules cli --launcher cli=cli/cli.Main --output dist --strip-debug --compress 2 --no-header-files --no-man-pages
-
--module-path
标志类似于CLASSPATH。它告诉工具应该在哪里查找已编译的模块二进制文件(即JAR文件或新的JMOD格式文件)。在这里,我们告诉它寻找项目的libs
子目录(因为这是Gradle放置可执行JAR的地方)以及标准库模块的JDK目录。 -
--add-modules
标志用于声明哪些模块要添加到结果包中。我们只需要声明自己项目的模块即可(cli
或gui
),因为 它 所依赖的模块将作为传递依赖被引入。 -
生成的包将包含
/bin
子目录,用于执行应用程序的bash脚本或Windows批处理文件。--launcher
标志允许你为这个脚本指定一个名字,以及它应该调用哪个Java类(这看起来有点多余,因为这已经在可执行JAR中指定了)。在上面的命令中,我们将创建一个名为bin/cli
的脚本,它将调用模块cli
中的cli.Main
类。 -
--output
标志直观地指定了放置结果包的子目录。在这里,我们使用一个名为dist
的目标目录。 -
最后,这些标志
--strip-debug
,--compress 2
,--no-header-files
和--no-man-pages
是我所做的一些优化,以减少产生的包的大小。
在项目的根目录下,这个Gradle命令建立并链接了两个子项目:
./gradlew linkAll
由此产生的可部署包可以在以下位置找到:
[PROJECT_ROOT]/cli/build/dist [PROJECT_ROOT]/gui/build/dist
结果
我们来看看链接出来的CLI和GUI应用程序的大小,以及精简的嵌入式JRE:
应用 | 原始大小 | 用7-zip压缩后的大小 |
---|---|---|
cli
|
21.7 MB | 10.8 MB |
gui
|
45.8 MB | 29.1 MB |
这是在Windows机器上,用64位的JRE打包打出来的结果(Linux包的大小有点大,但比例仍大致相同)。下面是一些注意事项:
-
作为比较,这个平台上完整的JRE大小是203MB。
-
用 Go 编写的“Hello World”命令行程序编译出来是2MB左右。 Hugo 是用于发布此博客的网站生成器,它是一个27.2MB大小的Go可执行文件。
-
对于跨平台的GUI开发,一个典型的Qt或GTK应用程序仅附带大约15MB的Windows DLL。 Electron快速开始例程 会生成一个131 MB的程序。
结论
说句公道话,一个包含启动脚本的应用程序包并不像“ 单单一个.EXE程序 ”那样简单。另外,由于JIT编译器的原因,JRE在启动时相对较为缓慢。
即便如此,Java仍然是一种能够生成大小与其他编译语言相媲美、独立的、零依赖的应用程序的语言(并且比Electron等Web混合程序更为优秀)。此外,Java 9 包含了一个实验性的AOT编译器
,这也许可以加速程序的启动。尽管这个 jaotc
工具最初只适用于64位 Linux 平台,但它很快就会扩展到其他平台。
虽然Go在早期的云基础设施CLI工具中备受瞩目(例如 Docker , Kubernetes 、 Consul 、 Vault 等),但Java正在成为一个强有力的替代者,特别是对于具有构建Java经验的项目组。对于跨平台桌面GUI应用程序,我认为JavaFX与Java 9模块化的结合是现在最好的选择。
1月13日, SDCC 2017之数据库线上峰会 即将强势来袭,秉承干货实料(案例)的内容原则,邀请了来自阿里巴巴、腾讯、微博、网易等多家企业的数据库专家及高校研究学者,围绕Oracle、 MySQL 、PostgreSQL、 Redis 等热点数据库技术展开,从核心技术的深挖到高可用实践的剖析,打造精华压缩式分享,举一反三,思辨互搏,报名及更多详情可点击此处查看。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:- Layui 2.1.6 发布,原生态模块化前端 UI 方案
- Android模块化改造以及模块化通信框架
- Laravel 模块化开发模块 – Caffienate
- ASP.NET Core模块化前后端分离快速开发框架介绍之4、模块化实现思路
- 前端模块化架构设计与实现(二|模块接口设计)
- JavaScript模块化
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
HTML Dog
Patrick Griffiths / New Riders Press / 2006-11-22 / USD 49.99
For readers who want to design Web pages that load quickly, are easy to update, accessible to all, work on all browsers and can be quickly adapted to different media, this comprehensive guide represen......一起来看看 《HTML Dog》 这本书的介绍吧!