- Contents -
jlinkでランタイム用のイメージを作成する。
この記事では、Java9以降のモジュールシステム(JPMS) を使ったアプリケーションを
JIMAGE(カスタムランタイム)という形で配布する方法について解説します。
JIMAGE形式では、配布先のPCにあらかじめ、Javaをインストールしておかなくても、
配布したファイルだけで、実行が可能になります。
Javaアプリケーションの配布方法
従来までは、配布先にJava(JRE)をあらかじめインストールしておいてもらい
作成したアプリケーション(jarファイルなど)を配布していました。
しかし、依存するJavaバージョンが異なるアプリケーションを複数併用したい場合、
すぐにJavaバージョンを上げる事ができません。
そこで、オラクルはJavaのアプリケーション配布方法として、次の方法を提唱しています。
アプリケーション開発者は、JIMAGE(カスタムランタイム)を生成して、
アプリケーション実行に必要なランタイムを内包した状態で配布する事。
Java9以降では、Javaコード自体がいくつかのモジュールにまとめらています。
そのおかげで、Javaはアプリケーションに必要最低限のランタイムコードだけをビルドする事ができるようになりました。
従来よりも、ランタイム配布サイズが小さくなります。
そして、Java11以降では、
オラクルが提供するOpenJDKから、JREのダウンロード提供はされなくなりました。
JIMAGEとは
いわゆるカスタムランタイムの事です。
イメージといっても、単一のファイルではない。
いくつかのディレクトリと、バイナリファイル郡が含まれます。
作成方法は、jlinkコマンドを使って、
リンクするモジュール(jmod, またはjarファイル)を指定するするだけで完成します。
依存するモジュールと、起点(ルート)になるモジュールを指定するだけです。
JIMAGEのファイル構成
先に成果物として出力される、
JIMAGE (カスタムランタイム)のファイル構成をお見せします。
$ tree -L 2 .
.
├── bin
│ ├── java
│ └── keytool
├── conf
│ ├── net.properties
│ └── security
├── include
│ ├── classfile_constants.h
│ ├── darwin
│ ├── jni.h
│ ├── jvmti.h
│ └── jvmticmlr.h
├── legal
│ └── java.base
├── lib
│ ├── classlist
│ ├── jli
│ ├── jrt-fs.jar
│ ├── jspawnhelper
│ ├── jvm.cfg
│ ├── libjava.dylib
│ ├── libjimage.dylib
│ ├── libjsig.dylib
│ ├── libnet.dylib
│ ├── libnio.dylib
│ ├── libosxsecurity.dylib
│ ├── libverify.dylib
│ ├── libzip.dylib
│ ├── modules
│ ├── security
│ ├── server
│ └── tzdb.dat
└── release
JREと似たような構成になっています。
binディレクトリには、javaコマンドがある。
このjavaコマンドには、jlinkで指定したモジュール群が含まれています。
アプリケーションの実行に必要な、モジュールはすべてこのディレクトリ構成に含まれているので、
これらをZip化して配布するだけで、配布先で実行することができます。
jlink コマンドの使い方
jlinkコマンドには、多くのオプションがありますが、
基本的には、モジュールの場所を指定して、起点になるルートモジュールを指定するだけです。
$ jlink -h
Usage: jlink <options> --module-path <modulepath> --add-modules <module>[,<module>...]
Possible options include:
--add-modules <mod>[,<mod>...] Root modules to resolve
--bind-services Link in service provider modules and
their dependences
-c, --compress=<0|1|2> Enable compression of resources:
Level 0: No compression
Level 1: Constant string sharing
Level 2: ZIP
--disable-plugin <pluginname> Disable the plugin mentioned
--endian <little|big> Byte order of generated jimage
(default:native)
-h, --help, -? Print this help message
--ignore-signing-information Suppress a fatal error when signed
modular JARs are linked in the image.
The signature related files of the
signed modular JARs are not copied to
the runtime image.
--launcher <name>=<module>[/<mainclass>]
Add a launcher command of the given
name for the module and the main class
if specified
--limit-modules <mod>[,<mod>...] Limit the universe of observable
modules
--list-plugins List available plugins
-p, --module-path <path> Module path
--no-header-files Exclude include header files
--no-man-pages Exclude man pages
--output <path> Location of output path
--post-process-path <imagefile> Post process an existing image
--resources-last-sorter <name> The last plugin allowed to sort
resources
--save-opts <filename> Save jlink options in the given file
-G, --strip-debug Strip debug information
--suggest-providers [<name>,...] Suggest providers that implement the
given service types from the module path
-v, --verbose Enable verbose tracing
--version Version information
@<filename> Read options from file
ここでは特に重要なオプションだけ説明しておきます。
jlinkには依存するモジュール(jmod, またはモジュール化したjarファイル)の場所を指定します。
--module-path
依存するモジュールを含めて、jmodファイルの場所を指定します。
(ディレクトリPATHでも、ファイルPATHでもOK)
コロンで複数指定可能。
jmodファイルじゃなくても、モジュール化したjarファイルを使ってもOK。
--add-modules
起点となる、ルートのモジュール名を指定する。(最低1つは必要)
ファイルPATHじゃなくて、モジュール名。
複数指定することも可能。(カンマで区切る)
jlinkは、ルートモジュールを起点に依存するモジュールを探索する。
ルートモジュール、依存モジュールが全て、
--module-pathで指定した場所に存在する必要がある。
($JAVA_HOME/jmods は暗黙的に含まれている)
--launcher
--launcher スクリプト名称=モジュール名/メインクラス名
binディレクトリに、起動用のスクリプト生成してくれる。
Linux/Macの場合、shellスクリプト。
Windowsなら、batファイルが生成される。
ランタイムイメージを作ってみよう
1. モジュール化したjarファイルを用意
module-info.java を含めてモジュール化したjarファイルを作成しましょう。
2. jmodファイルを作成
jlinkする際は、自分で作成したアプリケーションのJMODファイルか、
ネイティブコードに依存しないのであれば、モジュール化したjarファイルだけで大丈夫です。
今回はせっかくなので、jmodファイルにしておきます。
jmodファイルを作成するには、jmodコマンドを使います
mkdir -p out/jmods
jmod create \
--class-path build/libs/sample-1.0-SNAPSHOT.jar \
out/jmods/net.tyablog.sample.jmod
class-pathに指定してるのが、モジュール化(module-info.javaを含む)したjarファイルです。
出力ファイルは、モジュール名称と同じにしておくのが間違いありません。
拡張子は.jmod
を使います。
3. jlink でイメージを作成
mkdir -p out/jimage
jlink \
--module-path out/jmods \
--add-modules net.tyablog.sample \
--compress=2 \
--no-header-files \
--no-man-pages \
--output out/jimage
4. 完成!
binディレクトリのjavaコマンドにはすでにモジュールが組み込まれた状態になっています。
実行モジュール名/メインクラス名を指定するだけで、実行可能な状態。
$ ./out/jimage/bin/java -m net.tyablog.sample/net.tyablog.sample.Sample
hello
起動スクリプトの用意 (launcherオプション)
--launcherオプションを指定すると、起動用のスクリプトを生成してくれます。
スクリプトの内容は上記のモジュール名/メインクラス名を指定しただけのものです。
jlink \
--module-path out/jmods \
--add-modules net.tyablog.sample \
--launcher sample=net.tyablog.sample/net.tyablog.sample.Sample \
--compress=2 \
--no-header-files \
--no-man-pages \
--output out/jimage
さっきと違うのはこの部分。
--launcher sample=net.tyablog.sample/net.tyablog.sample.Sample
sampleとなってるところが、スクリプト名になるので、お好きな名称で大丈夫。
$ ./out/jimage/bin/sample
hello
まとめ
-
Java9以降のアプリケーションは、JIMAGE(カスタムランタイム)を生成して同梱した状態で配布ができる。
オラクルが提唱しているが、javaのセキュリティアップデートなどは
アプリケーション配布者が責任をもつ必要がある。
(更新物の配布など) -
JIMAGEは、アプリケーションに必要なモジュールだけが入ったバイナリファイル群。
アプリケーションのクラスファイルや、依存モジュールが全て含まれている。
そのままだと、ディレクトリ構造になっているので、
Zipでアーカイブして配布するのが良い。 -
jlinkコマンドは、ルートモジュール(--add-modules)を起点に、依存モジュールを探索する。
-
--launcherオプションで、起動ようのスクリプトを生成することができる。
中身は、javaコマンドにJVMオプション、実行モジュール名/メインクラス名を指定している。
1件のコメント