Java 11

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

Java 9以降のこと

これまでの実行可能Jar

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

これから

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

Jigsawモジュールシステム

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

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

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

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

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のエクスポート(MavenJREあり、ランチャー)

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

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使いたい場合?