OSGiには、分割パッケージ、つまり同じパッケージであるが複数のバンドルでホストされているパッケージに問題があります。
分割パッケージがプレーンJava(OSGiなし)で問題を引き起こす可能性があるエッジケースはありますか?
ちょっと興味があるんだけど。
パッケージの分割(OSGi の場合) は、マニフェスト ヘッダーRequire-Bundle
が使用されたときに発生します (Eclipse のマニフェストの場合と同様です)。Require-Bundle
クラスの検索に使用される他のバンドルに名前を付けます (パッケージがImport
編集されていない場合)。検索は、バンドル自体のクラスパスが検索される前に行われます。これにより、1 つのパッケージのクラスを複数のバンドル (おそらく個別の jar)のエクスポートからロードできます。
OSGi 仕様 (4.1) セクション 3.13Require-Bundle
では、このヘッダーを使用した場合の (予期しない) 結果の長いリストが説明されています (このヘッダーは非推奨にする必要がありますか? )。これらの結果のいくつかは奇妙です (そしてむしろ OSGi 固有のものです) が、次の 1 つのことを理解すればほとんどは回避できます。
パッケージの断片が切り離されている場合は、すべて問題ありませんが、クラスがどこからでも見えるわけではなく、分割されたパッケージの「間違った」部分から見た場合、パッケージの可視性メンバーが非公開に見えることがあります。
[もちろん、これは単純すぎます。パッケージの複数のバージョンをインストールできますが、アプリケーションの観点からは、パッケージのすべてのクラスは常に単一のモジュールから取得する必要があります。]
標準の Java では、手の込んだクラスローダがなくても、クラスパスがあり、クラスをロードするための jar (およびディレクトリ) の検索順序は固定されており、明確に定義されています。(しかし、私たちは扱いやすいモジュール性を放棄します。)
確かに、分割パッケージを使用することはできます (実際には非常に一般的です)。これは、モジュール性が低いことを示しています。徴候はあいまいなコンパイル/ビルド時のエラーである可能性がありますが、複数のクラス実装 (1 つのクラスパスで残りのクラスをオーバーライドする) の場合、ほとんどの場合、微妙に異なるセマンティクスのためにあいまいな実行時の動作を生成します。 .
運が良ければ、間違ったコードを見て、気付かないうちに、「でも、どうしてそんなことができるんだろう?」と自問することになります。
運が悪ければ、正しいコードを見て、まったく同じことを尋ねていることになります。別の何かが予期しない答えを生成していたからです。
これは、古いデータベースの格言「同じ情報を 2 か所に記録すると、すぐに同じ情報ではなくなる」とまったく違うわけではありません。私たちの問題は、「すぐに」というのは、通常、すぐには十分ではないということです。
各バンドルが独自のクラスローダーを使用するため、名前に関係なく、異なるバンドル内の OSGi パッケージは異なります。これは問題ではなく、バンドルのカプセル化を保証するための機能です。
したがって、プレーンな Java では、クラス ローダーを使用するフレームワークを使い始めるまで、これは通常問題になりません。これは通常、コンポーネントがロードされる場合です。
パッケージをjarに分割することは、おそらく良い考えではありません。jarファイル内のすべてのパッケージを封印することをお勧めします("Sealed: true"
マニフェストのメインセクションに配置します)。密封されたパッケージは、jarファイル間で分割できません。
OSGiの場合、パッケージ名が同じでクラスローダーが異なるクラスは、異なるパッケージにあるかのように扱われます。
同じパッケージ内にクラスがあり、署名済みの JAR にあるクラスとそうでないクラスがある場合、厄介な実行時エラーが発生します。
問題のパッケージはあなたのものであり、サードパーティのコードではないためですか?
簡単な例は、個別の OSGi バンドルとしてサービス レイヤーと永続化レイヤーを備えた Web アプリです。永続性インターフェイスは、両方のバンドルで共有する必要があります。
あなたの質問を正しく解釈した場合、解決策は、共有インターフェースを含む封印された JAR を作成し、それを両方のバンドルの一部にすることでしょうか?
スレッドを乗っ取ろうとするつもりはありません。これまでに OSGi を使って私よりも多くのことを行ってきた人たちから、明確化とより良い洞察を求めています。