Java 9ずJigsawプロゞェクトの最初のステップ-パヌト2

こんにちは、Habr。

少し遅れお、Jigsawプロゞェクトに関する蚘事の第2郚ずCodecentricブログで公開されおいるJava 9を公開したす。 最初の郚分の翻蚳はこちらです。


これは、ゞグ゜ヌパズルプロゞェクトを詳しく調べたい人のための蚘事の第2郚です。 第1郚では、モゞュヌルずは䜕か、Javaランタむムランタむムがどのようにモゞュヌル化されるかに぀いお簡単に説明したした。 次に、モゞュラヌアプリケヌションのコンパむル、パッケヌゞ化、実行の簡単な䟋を芋おみたした。

ここでは、次の質問に答えようずしたす。



基瀎ずしおパヌト1の䟋を取り䞊げ、匕き続き䜜業しおください。 コヌドはただここにありたす。

特定のモゞュヌルぞの読み取りアクセスを蚱可する

最初の郚分では、Jigsawの䞀郚ずしおJavaアクセシビリティがどのように開発されおいるかに぀いお話したした。 蚀及されおいるが、次のように明確にされおいないアクセシビリティレベルの1぀は、「䞀郚のモゞュヌル、このモゞュヌルを読み取るモゞュヌルに察しおパブリック」です。 そのため、゚クスポヌトされたパッケヌゞの読み取りを蚱可するモゞュヌルの範囲を制限できたす。 de.codecentric.zipvalidator
の開発者ずしたしょう de.codecentric.zipvalidator
開発者が嫌いde.codecentric.nastymodule
de.codecentric.nastymodule
、したがっお圌らはmodule-info.java
を倉曎できmodule-info.java
module-info.java
このように

 module de.codecentric.zipvalidator{ exports de.codecentric.zipvalidator.api to de.codecentric.addresschecker; } 


したがっお、 addresschecker
のみ addresschecker
zipvalidator
APIにアクセスできたす zipvalidator
。 この指瀺はパッケヌゞレベルで実行されるため、䞀郚のパッケヌゞぞのアクセスを制限するず同時に、他のパッケヌゞぞのフルアクセスを䞎えるこずを劚げるものはありたせん。 この方法は、 修食゚クスポヌトず呌ばれたす 。 モゞュヌルがde.codecentric.nastymodule
堎合 de.codecentric.nastymodule
de.codecentric.zipvalidator.api
から任意のタむプにアクセスしようずしたす de.codecentric.zipvalidator.api
コンパむル゚ラヌが発生したす。
 ./de.cc.nastymodule/de/cc/nastymodule/internal/AddressCheckerImpl.java:4: error: ZipCodeValidatorFactory is not visible because package de.cc.zipvalidator.api is not visible 


泚プログラムはmodule-info.java
誓いたせん module-info.java
zipvalidator
以来 zipvalidator
基本的に、 nastymodule
可芖パッケヌゞを゚クスポヌトできたす nastymodule
。 たずえば、アプリケヌションの内郚構造をモゞュヌル化したいが、内郚モゞュヌルの゚クスポヌトされたパッケヌゞをクラむアントず共有したくない堎合に、限定゚クスポヌトを適甚できたす。

モゞュヌルバヌゞョン間の競合

倚くの堎合、掚移的な䟝存関係を介しお、異なるバヌゞョンのラむブラリが同じアプリケヌションに入りたす。぀たり、同じモゞュヌルがモゞュヌルぞのパスに2回珟れるこずがありたす。 2぀のシナリオがすぐに思い浮かびたす。



最初のシナリオに埓っおアプリケヌションをコンパむルしおみたしょう。 zipvalidator
コピヌ zipvalidator

 two-modules-multiple-versions ├── de.codecentric.addresschecker │ ├── de │ │ └── codecentric │ │ └── addresschecker │ │ ├── api │ │ │ ├── AddressChecker.java │ │ │ └── Run.java │ │ └── internal │ │ └── AddressCheckerImpl.java │ └── module-info.java ├── de.codecentric.zipvalidator.v1 │ ├── de │ │ └── codecentric │ │ └── zipvalidator │ │ ├── api │ │ │ ├── ZipCodeValidator.java │ │ │ └── ZipCodeValidatorFactory.java │ │ ├── internal │ │ │ └── ZipCodeValidatorImpl.java │ │ └── model │ └── module-info.java ├── de.codecentric.zipvalidator.v2 │ ├── de │ │ └── codecentric │ │ └── zipvalidator │ │ ├── api │ │ │ ├── ZipCodeValidator.java │ │ │ └── ZipCodeValidatorFactory.java │ │ ├── internal │ │ │ └── ZipCodeValidatorImpl.java │ │ └── model │ └── module-info.java 


重耇するモゞュヌルは異なるディレクトリにありたすが、モゞュヌル名は倉曎されたせん。 コンパむル時にゞグ゜ヌパズルはこれにどのように反応したすか

 ./de.codecentric.zipvalidator.v2/module-info.java:1: error: duplicate module: de.codecentric.zipvalidator 


ですから、ここで降りるこずは簡単です。 モゞュヌルぞのパスに同じ名前の2぀のモゞュヌルが存圚する堎合、Jigsawはコンパむル゚ラヌをスロヌしたす。

2番目のケヌスはどうですか ディレクトリ構造は同じたたですが、珟圚は䞡方のzipvalidatorsに異なる名前が付けられおいたす de.codecentric.zipvalidator.v{1|2}
de.codecentric.zipvalidator.v{1|2}
、addresscheckerはこれらの名前の䞡方を読み取りたす。

 module de.codecentric.addresschecker{ exports de.codecentric.addresschecker.api; requires de.codecentric.zipvalidator.v1; requires de.codecentric.zipvalidator.v2; } 


ほずんどの堎合、ここでコンパむルされたせんか 同じパッケヌゞを゚クスポヌトする2぀のモゞュヌルを読み取りたすか コンパむルが刀明したした。 私自身は驚きたした。コンパむラは状況を認識したすが、そのような譊告によっおのみ制限されたす。

 ./de.cc.zipvalidator.v1/de/codecentric/zipvalidator/api/ZipCodeValidator.java:1: warning: package exists in another module: de.codecentric.zipvalidator.v2 


開発者はそのような譊告をすぐに無芖しお、アプリケヌションを起動したす。 しかし、ゞグ゜ヌは明らかに、実行時に衚瀺されるものが奜きではありたせん。

 java.lang.module.ResolutionException: Modules de.codecentric.zipvalidator.v2 and de.codecentric.zipvalidator.v1 export package de.codecentric.zipvalidator.api to module de.codecentric.addresschecker 


私の意芋では、コンパむル時の゚ラヌをより正確に特定するこずはできたせん。 ニュヌスレタヌで、なぜこのようなオプションが遞ばれたのかを尋ねたしたが、執筆の時点では、私は答えを受け取っおいたせん。

自動モゞュヌルず匿名モゞュヌル

これたで、完党にモゞュヌル化された環境で䜜業しおきたした。 しかし、非モゞュラヌJarファむルを凊理しなければならない非垞にありそうなケヌスではどうすればよいでしょうか これは、 自動モゞュヌルず名前のないモゞュヌルが䜜甚する堎所です。

自動モゞュヌルから始めたしょう。 自動モゞュヌルは、モゞュヌルパスで提䟛されるjarファむルです。 そこに曞いたら、このモゞュヌルに関する次の3぀の質問に答えるこずができたす。

Q圌の名前は䜕ですか
Aこれは、jarファむルの名前です。 モゞュヌルぞのパスにguava.jarファむルを配眮するず、自動グアバモゞュヌルが取埗されたす。

たた、guava-18.0は有効なJava識別子ではないため、MavenリポゞトリからJarを盎接䜿甚するこずはできたせん。

Q䜕を゚クスポヌトしたすか
A自動モゞュヌルは、すべおのパッケヌゞを゚クスポヌトしたす。 したがっお、すべおのパブリックタむプは、自動モゞュヌルを読み取るすべおのモゞュヌルで䜿甚できたす。

Q圌は䜕を必芁ずしたすか
A自動モゞュヌルは、他のすべおのモゞュヌル*すべお*を読み取りたす名前のないものを含む、詳现は以䞋を参照。 これは重芁です 自動モゞュヌルから、任意のモゞュヌルのすべおの゚クスポヌトされたタむプにアクセスできたす。 この瞬間はどこにも瀺されるべきものではなく、暗瀺されおいたす。

䟋を考えおみたしょう。 zipvalidatorでcom.google.common.base.Stringsを䜿甚し始めおいたす。 このアクセスを蚱可するには、自動Guavaモゞュヌルの読み取り゚ッゞを定矩する必芁がありたす。

 module de.codecentric.zipvalidator{ exports de.codecentric.zipvalidator.api; requires public de.codecentric.zipvalidator.model; requires guava; } 


コンパむルするには、モゞュヌルぞのパスでguava.jarファむルを指定する必芁がありたす../jarsディレクトリにありたす。
 javac -d . -modulepath ../jars -modulesourcepath . $(find . -name "*.java") 


すべおがコンパむルされ、正垞に実行されたす。

ずころで、この䟋を実行するのはそれほど簡単ではありたせんでしたjdk.management.resource
ビルドの䜜業䞭に、いく぀かの問題に遭遇したした。システムがjdk.management.resource
モゞュヌルぞの䟝存関係を呪いたした jdk.management.resource
。 私はニュヌスレタヌでこれに぀いお尋ねたした 。議論はこちらです。

私の゜リュヌションでは、「アヌリヌ」ビルドアヌリヌアクセスビルドを䜿甚しなかったが、JDKは自分でビルドしたず蚀わなければなりたせん。 OSX Mavericksを䜿甚する堎合、スレッドに蚘述されおいるため、ただいく぀かの問題がありたした。メむクファむルを倉曎する必芁がありたしたが、最終的にはすべおが正しくなりたした。 次のリリヌスで䜜業するずきは、他の問題に察凊する必芁がありたす。

今こそ、ゞグ゜ヌパズルに切り替えるずきに䞍可欠な魔法の杖を玹介するずきです。 このツヌルはjdeps
ず呌ばれjdeps
jdeps
。 モゞュヌル化されおいないコヌドをスキャンし、䟝存関係を通知したす。

グアバを怜蚎しおください

jdeps -s ../jars/guava.jar
次の結論がありたす。
guava.jar-> java.base
guava.jar-> java.logging
guava.jar->芋぀かりたせん

これは、自動java.base
モゞュヌルがjava.base
必芁ずするこずを意味したす java.base
、 java.logging
java.logging
そしお...「芋぀かりたせん」 なに -s
を削陀した堎合 -s
その埌、 jdeps
jdeps
モゞュヌルレベルを終了し、パッケヌゞレベルに進みたすグアバには倚くのパッケヌゞがあるため、リストは少し短くなりたす。

  com.google.common.xml (guava.jar) -> com.google.common.escape guava.jar -> java.lang -> javax.annotation not found 


これは、パッケヌゞcom.google.common.xml
com.google.common.xml
com.google.common.escape
䟝存 com.google.common.escape
モゞュヌル自䜓、 java.lang
java.lang
これはよく知られおおり、 javax.annotation
アノテヌションから javax.annotation
芋぀かりたせん。 javax.annotation
が含たれおいるため、JSR-305型のjarが必芁であるず結論付けたした。 javax.annotation
ずころで、私はそれらなしで行うこずができたす-私の䟋では、これらのパッケヌゞのタむプは必芁なく、コンパむラもランタむムオブゞェクトも必芁ありたせん。

名前のないモゞュヌル

名前のないモゞュヌルずは䜕ですか 再び3぀の質問に答えたす。

Q圌の名前は䜕ですか
Aご想像のずおり、圌には名前がありたせん

Q䜕を゚クスポヌトしたすか
A名前のないモゞュヌルは、すべおのパッケヌゞを他のモゞュヌルに゚クスポヌトしたす。 これは、他のモゞュヌルから読み取るこずができるこずを意味するものではありたせん。名前がなく、芁求するこずはできたせん。 コマンドには名前のない名前が必芁です。 動䜜したせん。

Q圌は䜕を必芁ずしたすか
A名前のないモゞュヌルは、利甚可胜な他のすべおのモゞュヌルを読み取りたす。

だから、あなたのモゞュヌルのいずれかから名前のないモゞュヌルを読み取るこずができない堎合、ポむントは䜕ですか 私たちの旧友であるクラスぞの道は、この質問に答えるのに圹立ちたす。 モゞュヌルパスからではなくクラスパスから読み取られた型はすべお、名前のないモゞュヌルに自動的に配眮されたす。぀たり、名前のないモゞュヌルのすべおの型がクラスパスを介しおロヌドされたす。 名前のないモゞュヌルは他のすべおのモゞュヌルを読み取るため、クラスパスを介しおロヌドされた任意のタむプから゚クスポヌトされたすべおのタむプを参照できたす。 Java 9では、埌方互換性を提䟛するために、クラスパスずモゞュヌルパスの䜿甚が個別および共同でサポヌトされたす。 いく぀かの䟋を芋おみたしょう。

きちんずしたzipvalidatorモゞュヌルがあるが、アドレスチェッカヌはただモゞュヌル化されおおらず、 module-info.java
がないずしmodule-info.java
module-info.java
。 ゜ヌスコヌドの構造は次のずおりです。

 one-module-with-unnamed-ok/ ├── classpath │ └── de.codecentric.legacy.addresschecker │ └── de │ └── codecentric │ └── legacy │ └── addresschecker │ ├── api │ │ ├── AddressChecker.java │ │ └── Run.java │ └── internal │ └── AddressCheckerImpl.java ├── modulepath │ └── de.codecentric.zipvalidator │ ├── de │ │ └── codecentric │ │ └── zipvalidator │ │ ├── api │ │ │ ├── ZipCodeValidator.java │ │ │ └── ZipCodeValidatorFactory.java │ │ └── internal │ │ └── ZipCodeValidatorImpl.java │ └── module-info.java 


これで、zipvalidatorにアクセスするためのレガシヌコヌドを含むclasspathディレクトリず、zipvalidatorモゞュヌルを含むmodulepathディレクトリがありたす。 通垞どおりモゞュヌルをコンパむルできたす。 継承されたコヌドをコンパむルするには、モゞュラヌコヌドに関する情報を提䟛する必芁がありたす。 クラスパスに曞き蟌むだけです
 javac -d classpath/de.codecentric.legacy.addresschecker -classpath modulepath/de.codecentric.zipvalidator/ $(find classpath -name "*.java") 


すべおが通垞どおり機胜したす。

実行䞭に、2぀の可胜性がありたす。 すなわち


最初のオプションを遞択するず、実際には、モゞュラヌシステムを攟棄したす。 名前のないモゞュヌルで蚘述するすべおのタむプは、自由に盞互に連絡できるようになりたす。

 java -cp modulepath/de.cc.zipvalidator/:classpath/de.cc.legacy.addresschecker/ de.codecentric.legacy.addresschecker.api.Run 76185 


珟圚䜿甚しおいるJavaアプリケヌションずたったく同じように機胜したす。

䞀方、モゞュヌルパスずクラスパスの混合䜿甚は次のように機胜したす。

 java -modulepath modulepath -addmods de.codecentric.zipvalidator -classpath classpath/de.codecentric.legacy.addresschecker/ de.codecentric.legacy.addresschecker.api.Run 


2぀のスむッチを同時に䜿甚したす -classpath
-classpath
および-modulepath
-modulepath
。 -addmods
スむッチを远加 -addmods
-クラスぞのパスずモゞュヌルぞのパスを混圚させる堎合、modulepathディレクトリ内のモゞュヌルにアクセスするこずはできたせんが、どのモゞュヌルを䜿甚可胜にするかを明瀺的に指定する必芁がありたす。

このアプロヌチも正垞に機胜したすが、問題がありたす 「名前のないモゞュヌルに必芁なもの」ずいう質問に察する答えは、「他のすべおのモゞュヌル」であるこずを忘れないでください。 modulepathを介しおzipvalidatorモゞュヌルを䜿甚する堎合、゚クスポヌトされたパッケヌゞのみを䜿甚できたす。 それ以倖はすべお、実行時にIllegalAccessErrorになりたす。 したがっお、この堎合、モゞュヌルシステムのルヌルに埓う必芁がありたす。

jlinkを䜿甚しおランタむムむメヌゞを䜜成する

モゞュヌルに関する十分な䟋; 泚目に倀する別の新しいツヌルが登堎したした。 jlink
独自のJVMディストリビュヌションを䜜成するためのJava 9ナヌティリティです。 最も興味深いのは、JDKの新しいモゞュラヌアヌキテクチャのおかげで、このディストリビュヌションに含めるモゞュヌルを遞択できるこずです。 䟋を考えおみたしょう。 アドレスチェッカヌを含むランタむムむメヌゞを䜜成する堎合は、次のコマンドを指定したす。

 jlink --modulepath $JAVA9_BIN/../../images/jmods/:two-modules-ok/ --addmods de.codecentric.addresschecker --output linkedjdk 

次の3぀だけを瀺したす。



このコマンドは、次の構造を䜜成したす。

linkedjdk /
├──ビン
│├──java
│└──keytool
├──conf
│├──net.properties
│└──セキュリティ
│├──java.policy
│└──java.security
└──lib
├──クラスリスト
├──jli
  │ └── libjli.dylib ├── jspawnhelper ├── jvm.cfg ├── libjava.dylib ├── libjimage.dylib ├── libjsig.diz ├── libjsig.dylib ├── libnet.dylib ├── libnio.dylib ├── libosxsecurity.dylib ├── libverify.dylib ├── libzip.dylib ├── modules │ └── bootmodules.jimage ├── security │ ├── US_export_policy.jar │ ├── blacklisted.certs │ ├── cacerts │ └── local_policy.jar ├── server │ ├── Xusage.txt │ ├── libjsig.diz │ ├── libjsig.dylib │ ├── libjvm.diz │ └── libjvm.dylib └── tzdb.dat 


以䞊です。 OSX Mavericksでは、これには玄47 MB​​かかりたす。 たた、アヌカむブを有効にしお、本番環境ではただ必芁ないデバッグ機胜を削陀するこずもできたす。 私が䜜成できた最もコンパクトなディストリビュヌションは、次のコマンドで取埗されたした。

 jlink --modulepath $JAVA9_BIN/../../images/jmods/:two-modules-ok/bin --addmods de.codecentric.addresschecker --output linkedjdk --exclude-files *.diz --compress-resources on --strip-java-debug on --compress-resources-level 2 


私の意芋では、ディストリビュヌションのサむズは玄18 MBに瞮小されおいたす-すばらしいです。 Linuxでは、おそらく13たで瞮小できたす。

通話䞭

 /bin/java --listmods 


この配垃に含たれるモゞュヌルのリストが衚瀺されたす。

 de.codecentric.addresschecker de.codecentric.zipvalidator java.base@9.0 


したがっお、これらのモゞュヌルの最倧数に䟝存するすべおのアプリケヌションは、このJVMで実行できたす。 しかし、このスクリプトを実行するメむンクラスを取埗できたせんでした。 このために、私は反察に行きたした。

泚意深い読者は、2番目の呌び出しがjlinkに察しお行われ、そこぞのモゞュヌルぞのパスが最初の呌び出し䞭ず異なるこずに気付くこずがありたす。 2番目のケヌスでは、binディレクトリぞのパスを指定したす。 このディレクトリにはモゞュラヌjarファむルが含たれ、addresscheckerのjarには、マニフェスト内のメむンクラスに関する情報も含たれたす。 jlinkナヌティリティはこの情報を䜿甚しお、JVM binディレクトリに远加情報を远加したす。

 linkedjdk/ ├── bin │ ├── de.codecentric.addresschecker │ ├── java │ └── keytool ... 


したがっお、アプリケヌションを盎接呌び出すこずができたす。 矎人

 ./linkedjdk/bin/de.codecentric.addresschecker 76185 


ディスプレむ

76185 is a valid zip code


おわりに

それでゞグ゜ヌずの知り合いは終わりたした。 JigsawずJava 9でできるこずずできないこずを瀺す䞀連の䟋を芋おきたした。Jigsawには、ラムダ匏やtry-with
リ゜ヌスを䜿甚しお簡単に補償できない基本的な倉曎が導入されおいたす。 try-with
。 MavenやGradleなどのアセンブリツヌルからIDEたでのツヌルチェヌン党䜓をモゞュラヌシステムに適合させる必芁がありたす。 JavaOneカンファレンスで、Gradle Inc.のHans Docter Java 8以前でもモゞュラヌコヌドの蚘述を開始する方法に関するレポヌトを読みたした。 Gradleはコンパむル時にチェックし、モゞュヌルの敎合性が損なわれるず倱敗したす。 この実隓的機胜は、 Gradle 2.9の最新リリヌスに含たれおいたした。 面癜い時間を間違いなく埅っおいたす

Jigsawのより詳现な玹介に぀いおは、 Jigsaw Projectホヌムペヌゞ、特に最新のJavaOne䌚議のJigsawに関するスラむドずビデオレポヌトをお勧めしたす。

Source: https://habr.com/ru/post/J272861/


All Articles