順序
この記事は、主にJava9への移行に関するいくつかの予防策を研究しています。
移行タイプ
1.コードはモジュール式ではなく、最初にJDK9に移行してJDK9のAPIを使用します
2。コードもモジュール式に移行されます
注意すべきことがいくつかあります
読み取れないクラス
たとえば、sun.security.x509はjava9のjava.baseモジュールに分類されますが、モジュールはパッケージをエクスポートしません。
-add-exports java.base/sun.security.x509 =実行時に追加することにより、エクスポート設定を変更できます。
内部クラス
たとえば、sun.misc.unsafeはもともとOracle JDKチームを使用したいと考えていましたが、これらのクラスはあまりにも広く使用されているため、Java9は後方互換性を備えて妥協を行っていますが、これらのクラスをJDK.UNSPORTEDモジュールに分類し、読みやすさを制限しませんでした。
➜〜java -d jdk.unsupportedjdk.unsupported@9 exports com.sun.nio.fileexports sun.miscexports sun.reflectrequires java.base base basededopens sun.miscopens sun.reflect
削除されたクラス
java9はsun.misc.base64encoderを削除しました。この場合、java.util.base64など、代わりに他のAPIのみを使用できます。
ClassPath vsモジュールパス
Java9はモジュールシステムを導入し、独自のJDKもモジュール化され、ClassPathをブロックするためにモジュールパスが導入されました。つまり、Module-PathがJava9で好まれています。結局のところ、JDK自体はモジュラーです。アプリケーション自体がモジュラーでない場合、Java9は無名のモジュールと自動モジュールメカニズムを介して暗黙的にモジュール化されます。もちろん、ClassPathは、Module-Pathの使用など、Java9で引き続き使用できます。
モジュール性のない瓶は、ClassPathの名前のないモジュールとして分類されます。モジュールパスでは、自動モジュールとして自動的に作成されます(自動モジュールは、Transitiveがすべての名前付きモジュールと名前のないモジュールに依存し、独自のパッケージをエクスポートすることを宣言します)
パッケージ名は複数のモジュール(分割パッケージ)に表示されません
エクスポートはモジュール内の他のモジュールに指定できるため、複数のモジュールが同じパッケージ名をエクスポートすると、混乱を引き起こします。特に、これらの2つのモジュールを同時に必要とする他のクラスライブラリがある場合、どのモジュールを参照するかわかりません。
推移的依存関係
インターフェイスパラメーターまたはモジュールの型を返す場合、他のモジュールのクラスを使用する場合、依存する推移的モジュールを要求することをお勧めします。
円形の依存関係に注意してください
モジュールを設計するときは、可能な限り循環依存関係があるかどうかを検討してください。もしそうなら、それらを再設計する必要があります。
サービスを使用して、オプションの依存関係を実装します
サービスは、発信者と実装クラスの依存関係を切り離すのに特に適しています。インターフェイスに複数の実装クラスがある場合、発信者はすべての実装クラスを要求する必要はありませんが、要求インターフェイスを必要とし、サービスタイプを使用して実装クラスのインスタンスをロードします。デカップリングは、モジュールパスに実装モジュールを動的に追加することで実現されます。
モジュールバージョン管理
module-nfo.javaは宣言バージョン番号をサポートしていませんが、JARパッケージを作成するときは、-module-versionを設定できます。ただし、モジュールシステムがモジュールを検索すると、モジュール名を使用して検索します(モジュールパスに複数の重複モジュールがある場合、モジュールシステムは最初のモジュールを使用して、同じ名前の後続のモジュールを自動的に無視することがわかります)。バージョンの依存関係の問題は、モジュールシステムのソリューションの範囲内ではなく、Mavenなどの依存関係管理ツールに任されています。
モジュールリソースアクセス
モジュール化後、リソースファイルも保護され、モジュールはモジュール自体のリソースファイルのみにアクセスできます。クロスモジュールアクセスが必要な場合は、モジュールレイヤーを使用してターゲットモジュールを見つけ、ターゲットモジュールを呼び出してモジュールのリソースファイルをロードする必要があります。
反射の使用
これには、深い反射の問題が含まれます。いわゆる深い反射は、反射を通じてクラスの非公開要素を呼び出すことです。 Module-info.javaのエクスポートは、パッケージがパッケージが直接属するクラスのみを許可して、パブリック要素へのアクセスを許可し、非公開要素への反射呼び出しを許可しないことを宣言します。
リフレクションには、モジュールシステムで許可される特別な宣言が必要です(ディープリフレクションを許可するために開く宣言を使用して)。これにより、Springなどの反射を使用する多くのクラスライブラリが発生します。 2つのソリューションがあります。1つは、spring.beansなど、反射が必要なモジュールにパッケージ名を開くことです。もう1つは、モジュール全体を直接開くことです。
デフォルト-ILLEGAL-ACCESS =許可。この設定は、JAVA9でアクセスが許可されておらず、Java9でアクセスできない新しいパッケージには適用されないJava9の前のパッケージにのみ適用できます。 (モジュラーシステムに移行するときに拒否することをお勧めします)
ただし、モジュールシステムでは、パッケージ名は異なり、継承関係はありません。たとえば、com.service.func1およびcom.service.func2は異なるパッケージです。 com.serviceだけを開くことはできませんが、それらを個別に指定する必要があります。これにより、開く必要があるパッケージが増えます。したがって、モジュール全体を開く方が簡単な場合がありますが、比較的大まかなアプローチでもあります。上記の方法は、元のModule-info.javaで変更を加えることです。別の方法は、JavaまたはJavacを実行するときに指定されたコマンドを介して元の関係を変更することです。例えば
java ... -add-opens source-module/source-package =ターゲットモジュール
名前のないモジュールにエクスポートする必要がある場合、ターゲットモジュールはすべて無名です
もちろん、それが新しいシステムである場合、反射を使用することはお勧めしません。 MethodHandlesとVarhandlesを使用できます。
FAQと測定
classNotFoundException/noclassdeffounderror
たとえば、javax.xml.bind.jaxbexception、jaxbはjava.xml.bindモジュールに分類され、Javaの命名後に追加されます。
-add-modules java.xml.bind
トラブルを節約したい場合は、$ java_homeとすべてのサードパーティライブラリをモジュールパスに追加してから実行します
-add-modules all-module-path
メソッドJava.lang.classloader.defineclassへのxxxによる違法な反射アクセス
リフレクションは、古いシステムにはモジュールINFOがないため、Javaの命名にパラメーターを追加して変更します。
-add-opens java.base/java.lang = all-unnamed
依存関係モジュールを決定します
IDEまたはJDEPSによる分析
jdeps - クラスパス 'クラス/lib/*' -recursive -summary app.jar
JDEPSは単なる静的コード分析です。反射を使用するクラスがある場合、分析することはできません。手動で要求する必要があります。依存関係がオプションである場合、静的を必要とすることができます。
モジュール単位テストの読みやすさの問題
モジュールがユニットテストに使用される場合、ユニットテストモジュールには、ターゲットモジュールの読みやすさと反射機能を介して許可できます。さらに、スプリットパッケージの問題により、ユニットテストクラスのパッケージ名をターゲットモジュールパッケージ名と複製することはできません。 Mavenプロジェクトのテスト
まとめ
2つのステップでJava9に移動できます。最初に、あなたは最初にモジュール式ではなく、最初にJDK9でのみ実行されます。その後、あなたはモジュール式です。