Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save kaakaa/f68a1e581a46f8f04138 to your computer and use it in GitHub Desktop.
Save kaakaa/f68a1e581a46f8f04138 to your computer and use it in GitHub Desktop.

Project Jigsaw

まだJigsawを使った開発はできなそう(2015/3/25) => Jigsaw入ったJDK9 Build80が公開(2015/9月)

OpenJDK: Project Jigsaw

Recent traffic & working documents

Project Jigsaw: Phase Two
Goals & Requirements (DRAFT 3)
JEP 200: The Modular JDK
JEP 201: Modular Source Code
JEP 220: Modular Run-Time Images
JSR 376: Java Platform Module System
    Requirements

* [The Java Community Process(SM) Program - JSRs: Java Specification Requests - detail JSR# 376](https://www.jcp.org/en/jsr/detail?id=376 "The Java Community Process(SM) Program - JSRs: Java Specification Requests - detail JSR# 376")
  * JCP内のJSR376に関するページ
  * GradlewareのHansDockerが Expert Group に所属していることが分かる
* [Oracle Blogs 日本語のまとめ: [Java] Project Jigsaw: Modular run-time images](http://orablogs-jp.blogspot.jp/2014/12/project-jigsaw-modular-run-time-images.html "Oracle Blogs 日本語のまとめ: [Java] Project Jigsaw: Modular run-time images")
  * 日本語の説明
* [module/bootclass troubles with jdk9](http://mail.openjdk.java.net/pipermail/jigsaw-dev/2015-February/004181.html "module/bootclass troubles with jdk9")
  * 現在(2015/02, jdk9 b41)、JSR376が実装されてないため、まだ我々は"module land"にはいない(javac コマンドの modulepath オプションなどは使えない)
  * ただ、JDK内部のモジュール化は進んでおり、rt.jarやtools.jarは無くなっている(JEP220より)
    * rt.jar - ブートストラップクラス (Java プラットフォームのコア API を構成するランタイムクラス)
    * tools.jar - JDK のツールとユーティリティーをサポートするためにコア以外のクラスが含まれる
      * java.~やjavax.~パッケージは全てrt.jarに入ってる。tools.jarは使ってるかな?

Jigsaw紹介資料
-------------

[Modularity of the Java Platform (OSGi, Jigsaw and Penrose)](http://www.slideshare.net/martintoshev/modularity-of-the-java-platform-osgi-jigsaw-and-penrose "Modularity of the Java Platform (OSGi, Jigsaw and Penrose)")
* Modularizationの利点
  * システムの分離が容易になる
  * メンテナンスしやすく成る
  * "JAR Hell"問題の解決
    * 依存関係の中に異なるバージョンのjarを混在できない
  * modular systemの代表はOSGi
* OSGi
  * JSR8,291
  * OSGi Runtimeとはなにか
    * modular units(bundle)コンテナを実装するためのclass loading mechanism
    * bundleはOSGi Runtimeに対してサービスやコンポーネントを提供するjarファイルなど* を言う
    * OSGi Runtimeは再起動なしにbundleの起動、停止、インストール、アップデートが可能
  * OSGi bundleのMavenサポートは?
    * [Tycho home](https://eclipse.org/tycho/ "Tycho home")
      * Gradle版は [akhikhl/wuff](https://github.com/akhikhl/wuff "akhikhl/wuff")
* Jigsaw
  * Javaに対するOSGiライクなモジュールのビルトインサポート
  * JDKはmonolithic
  * JDK8では使用するJDKの機能を制限できる?
    * Javac -profile compact1|compact2|compact3
  * Jigsawはとても大きな変更なので、ecosystemを壊す恐れがある
  * Jigsawとはなにか?
    * Java Module Systemの基礎となるもの
    * Module JDKではjreフォルダは無いし、rt.jarもtools.jarも無い
      * 必要なAPIだけ使う
  * Jigsaw moduleとはなにか?
    * Javaクラス/ネイティブライブラリ/リソースの集合
    * 他のモジュールへの依存を示すメタファイル
    * OSGiのようなdynamicsは持っていない?
    * 一番の根幹と成るモジュールはjava.base
    * 他のモジュールへの依存はrequireによって表す

module org.sample.A@1.0 { require org.sample.B@[2.0,3.0) }

  * moduleのコンパイル方法
    * javacのmodulepathオプションで依存しているモジュールを指定する
    * [Jigsaw Quick Start](http://openjdk.java.net/projects/jigsaw/doc/quickstart.html "Jigsaw Quick Start")
  * moduleの管理方法
    * jmodでモジュールを管理する
    * jpkgでモジュールのパッケージングを行う
  * なぜJavaプラットフォームにOSGiを利用しない?
    * OSGiはパッケージング、デプロイ、実行時のmodularityに取り組んでおり、コンパイル時には使えない
  * Jigsawモジュール開発用のIDEは?
    * まだIDEによるサポートはされてない
  * Mavenサポートは?
    * まだない
    * でも重要
* JigsawとOSGiの相互運用は?
  * Project Penroseとして進められている
    * [OpenJDK: Penrose](http://openjdk.java.net/projects/penrose/ "OpenJDK: Penrose")
    * まだ始まったばかり
  * Penroseではmodule-info.jsonが提案されている
    * module-info.javaより一般的
    * jigsaw/OSGi それぞれ用のメタファイルを生成できるフォーマット


[Java 8 modules, Jigsaw and OSGi - Neil Bartlett](http://www.slideshare.net/mfrancis/java-8-modules-jigsaw-and-osgi-neil-bartlett?next_slideshow=1 "Java 8 modules, Jigsaw and OSGi - Neil Bartlett")

JDK 9: Highlights from The State of the Module System

Project Jigsaw and OSGi

  • JigsawはJavaのビルトイン機能なので、多くの情報が出てくる。なので、OSGiを使うよりは先があるだろうという論調。
  • ただ、JigsawはJava9以降でしか使えないが、OSGiはそれ以前のバージョンのJavaでも使用できる利点があるため、いますぐにJigsawへの移行を検討しなくてはいけないというわけではない

Javaのmodularization

  • Java9で追加される予定のProject Jigsaw周りを調べてみた

    • Javaのモジュラー化についての仕様 JSR376
    • 本来はJava7で追加される予定だった
  • jigsawはJava自身のOSGi化 *

The State of the Module System

The State of the Module System

2015/9/8 17:12 -0700 [72deb34d31df]

  • キーワード
  • module
  • type
  • artifact
  • package

Modules

  • Moduleはsekf-describing collection of code and data
  • 依存関係はモジュールのrequiresとパッケージのexportsで管理される
  • The access-control mechanisms of the Java language and the Java virtual machine prevent code from accessing types in packages that are not exported by their defining modules.
  • service interfaceをusesとその実装のためのprovidedがある

Module Declarations

  • モジュールの宣言
module com.foo.bar { }
  • 他モジュールへの依存の宣言
module com.foo.bar {
  requires com.foo.baz;
}
  • 他モジュールに対する公開の宣言
    • exportsされたパッケージ内のpublicな型が公開される
module com.foo.bar {
  requires com.foo.baz;
  exports com.foo.bar.aplpha;
  exoprts com.foo.bar.beta;
}
  • module-info.java
    • モジュール宣言はmodule-info.javaに記述される
    • module-info.javaはソースフォルダのトップに配置される(convention)
module-info.java
com/foo/bar/alpha/AlphaFactory.java
com/foo/bar/alpha/Alpha.java
  • module-info.javaはコンパイルされてmodule-info.classファイルとなり、同じ階層に置かれる
  • モジュール名はコンフリクトしてはいけない
    • そのため、exportsされるパッケージ名のprefixがモジュール名に使用される事が多い。しかし、それは強制ではない。
  • モジュール宣言はバージョン宣言を含んでない
    • 依存するモジュールのバージョンも指定していない
    • これはModule Systemがバージョン選択問題の解決を目的としていないから
    • これはビルドツールやコンテナの課題
  • モジュール宣言はjavaプログラミング
    • これはコンパイル時と実行時をなるべく同じ環境にして、エラー発生時の調査や修復を容易にするため

Module Artifacts

  • module-info.classを含むjarファイルをModular Jarとする
    • module-info.classを含む以外は既存のjarファイルと同じ
META-INF/
META-INF/MANIFEST.MF
module-info.class
com/foo/bar/alpha/AlphaFactory.class
com/foo/bar/alpha/Alpha.class
...
  • Modular Jarもclasspathに通せば普通のjarファイルとして使える
  • モジュールの新しいフォーマット JMOD を標準化している

Module descriptors

  • module-info.classはクラスファイルの形式
    • そうすることで、ビルドツールやIDEからattribute(バージョン、タイトル、説明、ライセンスなど)を追加したりもできる
    • また、調査やドキュメンテーション、デバッグにも使える
    • => MANIFESTファイルの役目を果たす?

Platform Modules

  • Java SE9 Platform自体も複数のモジュールに分割されている
  • Platformのコアパッケージはjava.baseで宣言され、exportsされている
module java.base {
    exports java.io;
    exports java.lang;
    exports java.lang.annotation;
    exports java.lang.invoke;
    exports java.lang.module;
    exports java.lang.ref;
    exports java.lang.reflect;
    exports java.math;
    exports java.net;
    ...
}
  • 他の全てのモジュール(Java SE9 Platformの?)はjava.baseに依存している
  • java.baseは他のモジュールに依存していない
  • 他のモジュール名はjava.で始まる。Java SE9 Platform Specificationに入ってないがJDKの仕様のものはjdk.で始まる

Module graphs

  • モジュールの推移的な依存関係の解決もしてくれる
  • 推移的な依存関係のグラフがModule graphs

Readability

  • 推移的な依存関係により解決されたモジュールはReadableでない(classpathと同じ考え方)
  • The readability relationships defined in a module graph are the basis of reliable configuration:
  • これは高速化に寄与する
    • モジュール内のコードがあるパッケージ内の型(type)を必要としているとき、自分自身のモジュール内と、そのモジュールがreadできる(readable)なモジュールの中だけを探しにいけば良い
      • 今までの様にclasspath内の全てを探索対象としなくても良い

Module Paths

  • Module Graphを構築する際、module systemはビルトインのモジュールか、modulepathで宣言された場所にあるartifactを内のモジュールをselectする
  • modulepathはclasspathとは違う
    • classpathはtypeがどのartifactに存在するかを気にしない
    • そのため、異なるartifact(全く異なるコンポーネント or 同コンポーネントのバージョン違い)内に同名のtypeが存在できてしまう(クラスをロードする際にエラーとなる)
  • modulepathは依存関係を解決出来ない時や同名モジュールを見つけた際にコンパイラ、もしくはVMがエラーを吐く
    • => おそらく、最初にModule graphを構築することで、依存関係周りの解決を行う(classpathだと必要になった時に探す)
    • => その分、起動時の時間は伸びそう?
    • => ホットデプロイとかはできなくなってそう?
  • Universe of Observable Modules
    • The modules built-in to the compile-time or run-time environment, together with those defined by artifacts on module paths, are collectively referred to as the universe of observable modules.

Accessibility

  • exportsしてないpackageやrequiresしてないpackageの使用はJVMのIllegalAccessErrorやReflective Runtime APIのIllegasAccessExceptionによって防がれる
    • publicで宣言しても使えなくなる

Implied Readability

  • A -> B -> Cの依存関係がある時にAからC内のtypeを使用したいことがある
  • 例えば com.foo.app -> java.sql -> java.loggingのモジュール依存関係があるとき
    • インタフェースjava.sql.Driverは public Logger getParentLogger();を持っている
    • Loggerクラスはjava.loggingモジュールの持ち物
    • com.foo.appで下記コードを書いた時どうなる?
String url = ...;
Properties props = ...;
Driver d = DriverManager.getDriver(url);
Connection c = d.connect(url, props);
d.getParentLogger().info("Connection acquired");
  • 例えば、java.sqlの作者がjava.loggingのラッパーを作成する
    • 無理
  • このようなimplied readabilityはmodule-infoのrequiresにてpublic modifierを付けることで解決する
module java.sql {
    requires public java.logging;
    requires public java.xml;
    exports java.sql;
    exports javax.sql;
    exports javax.transaction.xa;
}
  • => しかし、公開すべきモジュールと公開すべきでないモジュールの判断はモジュールの作者に委ねられることになるので心配
  • => また、依存関係の漏洩に繋がるので、あまり使わない方が良いのだろう。

Services

  • Service InterfaceとService Providerによる疎結合は大規模システムを作る時に有用だよねという入り
  • 今まではjava.util.ServiceLoaderによって達成されてきた
    • META-INF/servicesリソースディレクトリにservice-definitionを書く(置く?)ことでRuntime時にclasspathからService Providerを解決していた
      • => 使ったことね。やべ。
    • しかし、classpathでなくmodulepathを使うようになるので、どうするか、という話
  • 答えとしては、使われる側(Service Interface)をusesで宣言し、使う側ではprovides/withで宣言する
    • 使われる側(Service Interface)
module java.sql {
    requires public java.logging;
    requires public java.xml;
    exports java.sql;
    exports javax.sql;
    exports javax.transaction.xa;
    uses java.sql.Driver;
}
  • 使う側(Service Provider)
module com.mysql.jdbc {
    requires java.sql;
    requires org.slf4j;
    exports com.mysql.jdbc;
    provides java.sql.Driver with com.mysql.jdbc.Driver;
}

Reflection

  • java.lang.reflection.Moduleクラスでモジュール情報を扱える
    • Class::getModuleで取得する
package java.lang.reflect;

public final class Module {
    public String getName();
    public ModuleDescriptor getDescriptor();
    public ClassLoader getClassLoader();
    public boolean canRead(Module source);
    public boolean isExported(String packageName);
}
  • => これがこの節で言いたかったことなんかな…?なんか読み違えてる感が。
  • => Jigsawのメーリス見るとリフレクションのsetAccessibleメソッドが不明な例外を返すようになったとかで盛り上がってたような。クラスローダーの扱いも変わったとかなんとか。詳細不明。

Classloaders

  • クラスローダーも上手く作ってるよ

  • 既存のクラスローダーの仕組みと上手く結合してるよ

  • => クラスローダがあまり分かってないので、理解が薄い

Unnamed modules

  • クラスローダーはnamed moduleに欲しいtypeが無い場合、そのtypeがunnamed moduleに存在するものと解釈する
    • 既存のクラスパスに含めるものとの整合性を保つため
  • unnamed moduleはevery other modulesを読み込み、全てのパッケージをexportする
    • そのため、既存のclass-pathなapplicationは今まで通り動作する

Advanced Topic

Qualified exports

  • exports節にtoでモジュール名を指定することで、export先のモジュールを限定できる
module java.base {
    ...
    exports sun.reflect to
        java.corba,
        java.logging,
        java.sql,
        java.sql.rowset,
        jdk.scripting.nashorn;
}

Increasing Readability

  • reflectionのnewInstanceメソッドを使うときなどは、生成するクラスがaccessibleでなければならない
    • ランタイムでモジュールへの新たな依存関係を追加するときはModule#addReadsを使う
public final class Module {
    ....
    public Module addReads(Module source);
}
 XMLInputFactory.class.getModule()
        .addReads(providerClass.getModule());
        
before the invocation of the provider class’s newInstance method. (The use of XMLInputFactory.class in this fragment is not mandatory; any class in the java.xml module will do, since we just need to get a reference to that module’s Module object.)

Layers

  • layerはmodule graphとモジュールとクラスローダのマッピングをカプセル化する
    • boot layerはスタートアップ時にJVMによって作られる。ランタイムのビルトインobservable moduleとmodule pathのartifactから解決されるもの
    • 大抵のアプリはboot layerだけで十分だが、コンテナなどはnew layerを作る
    • 新しいlayerはboot layerの上に作られていき、あるlayerはそのlowerなlayerのモジュールを含んだmodule graphを作る(lower layerのモジュールを読み込める)

気になるところ

  • JREモジュールの中で使いたくないものがあるときはどうする?
    • modulesフォルダから削除する?
    • どこでjava.base、もしくは他のモジュールへの依存関係を張っている?
    • => おそらく、java.baseだけは暗黙的に依存関係がはられている
The base module is always present. Every other module depends implicitly upon the base module, while the base module depends upon no other modules.
  • Jigsawではコンパイル開始時、および実行時に、先ずModule Graphを作成する(はず)ので、起動時の時間は増えそうだけど、実際にはどうか?

  • A -> B -> Cでモジュールの依存関係が成り立っている時、AからCのtypeを参照したいときはどうすれば良い?

    • requires public hoge.fugaで解決する
      • => implied readability
  • しかし、Bの作者はCの何を公開すべきか考えなくてはいけない?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment