Java 11 JRE付きエクスポート

あんまり分かってないけど、とりあえずJRE付きでエクスポートまではできた。

Java 9以降のこと

これまでの実行可能Jar

  • Javaランタイム(JRE)を同梱しなくても、システムにインストールされたPublic JREで実行できた

これから

  • システムにJREがない
  • 同様に実行できるようにするには、JREをアプリケーションに同梱する必要がある(?)
    • これまでもrt.jarがJREの同梱された形としてあったはず

Jigsawモジュールシステム

Java 9以降導入されたJavaの依存関係システム。

依存関係はmodule-info.javaファイルに記述する。

module sample.module {
requires java.base; // 不要(省略可)
}

実行可能Jarのエクスポート(Maven、JREなし)

Java 8まで、こんな感じだった。

Maven pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.example.sample</groupId>
<artifactId>Sample</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<java.version>8</java.version>
<maven.compiler.source>${java.version}</maven.compiler.source>
<maven.compiler.target>${java.version}</maven.compiler.target>
</properties>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>3.1.1</version>
<configuration>
<archive>
<manifest>
<addClasspath>true</addClasspath>
<mainClass>com.example.sample.Main</mainClass>
</manifest>
</archive>
</configuration>
</plugin>
</plugins>
</build>
</project>

JREの生成(手動、module-info使用)

コンパイルしたクラスファイルのディレクトリを指定

jlink --module-path './classes;JDK_DIRECTORY/jmods' --add-modules sample.module --output jre

Jarを指定

jlink --module-path './sample.jar;JDK_DIRECTORY/jmods' --add-modules sample.module --output jre

圧縮

-c 2

起動用スクリプトも生成してくれる。

--launcher mycmd=sample.module/com.example.sample.Main

OpenJDK 11.0.1 (Windows)で実行すると、dll, exe, ランチャーシェルスクリプト, bat他が生成された。OpenJDKの中身を絞って移してきてる? 複数OS想定する場合、JREはOS別に作る必要があるのか? それとも別の方法があるのか。

実行可能Jarのエクスポート(Maven、JREあり、ランチャー)

上の処理を自動化してくれるプラグインを使う。

ant-runの部分はjlinkツールが出力ディレクトリを上書きしてくれないので、packageを実行するごとに削除させるため。手動で消すかcleanすれば不要。

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.example.sample</groupId>
<artifactId>Sample</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<java.version>11</java.version>
<maven.compiler.source>${java.version}</maven.compiler.source>
<maven.compiler.target>${java.version}</maven.compiler.target>
</properties>
<build>
<plugins>
<!-- https://mvnrepository.com/artifact/org.moditect/moditect-maven-plugin -->
<plugin>
<groupId>org.moditect</groupId>
<artifactId>moditect-maven-plugin</artifactId>
<version>1.0.0.Beta2</version>
<executions>
<execution>
<id>create-runtime-image</id>
<phase>package</phase>
<goals>
<goal>create-runtime-image</goal>
</goals>
<configuration>
<compression>2</compression>
<modulePath>
<path>${project.build.outputDirectory}</path>
</modulePath>
<modules>
<module>sample.module</module>
</modules>
<launcher>
<name>Sample</name>
<module>sample.module/com.example.sample.Main</module>
</launcher>
<outputDirectory>
${project.build.directory}/jlink
</outputDirectory>
</configuration>
</execution>
</executions>
</plugin>
<!-- https://mvnrepository.com/artifact/org.apache.maven.plugins/maven-antrun-plugin -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-antrun-plugin</artifactId>
<version>1.8</version>
<executions>
<execution>
<phase>initialize</phase>
<goals>
<goal>run</goal>
</goals>
<configuration>
<target>
<delete dir="${project.build.directory}/jlink" quiet="true" />
</target>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>

ただ、この方法だとjarファイルが見当たらない。たぶんruntimeも自分のプログラムも混ざってどこかに入ってる。外部jarを混ぜずに読み込む方法もわからない。

JREの生成(手動、Jar使用)

module-infoを使わない方法(使わないでいいのかは分からないけど)。

jdeps --list-deps JARファイルmodule-infoのないJARの依存するモジュールリストが出力される。

このリストをもとに下のコマンドでJREを生成すれば混ざることはないはず。

jlink -c 2 -p 'JDK_DIRECTORY/jmods' -m モジュールカンマ区切りリスト --output jre

生成されたjava実行ファイルに対してjava -jar JARファイルするスクリプトを書けば外にjarを置ける。

外部Jarライブラリをlibsディレクトリに置く、というのを次はやりたい。今まで通りクラスパスに追加して、JREだけ上の方法で生成する、実行はスクリプトから、は正解じゃない気がするので、どうすればいいのか。それから、Launch4j使いたい場合?