1Z0-826-JPN 対応
モジュール(サービス provides / uses)難易度 高無料

サービスを3モジュールで構成する。

1   // ===== API モジュール =====
2   module com.pay.api {
3       exports com.pay.api;             // interface PaymentService
4   }
5   // ===== プロバイダ モジュール =====
6   module com.pay.stripe {
7       requires com.pay.api;
8       provides com.pay.api.PaymentService
9           with com.pay.stripe.StripePayment;   // 実装クラス
10  }
11  // ===== コンシューマ モジュール =====
12  module com.shop {
13      requires com.pay.api;
14      uses com.pay.api.PaymentService;
15  }

com.shop は ServiceLoader.load(PaymentService.class) でプロバイダを取得する。StripePayment が ServiceLoader で正しく発見・生成されるための要件として正しいものを選べ。

  1. Acom.pay.stripe は実装クラス StripePayment を exports しなければならない(さもないと ServiceLoader が見つけられない)。
  2. BStripePayment が public で、public な引数なしコンストラクタ(または public static な provider() メソッド)を持てばよい。実装クラスを exports する必要はない。
  3. Ccom.shop の module-info に requires com.pay.stripe; も追加しないとプロバイダを発見できない。
  4. Duses 宣言は不要。ServiceLoader.load は uses なしでも全モジュールを走査して自動発見する。
正解・解説・誤答理由・ひっかけを見る▼ open
✓ 正解:B✓有資格者監修

解説

JPMS のサービス機構は「実装を隠したまま、インタフェースだけで疎結合に繋ぐ」のが目的。配線は module-info の宣言で行う。

プロバイダ側の provides … with … が「このインタフェースの実装はこれ」とモジュールシステムに登録する。 だから実装クラスを exports する必要はない(むしろ exports すると実装が漏れて疎結合が崩れる)。モジュールシステムが実装をリフレクティブに生成するため、実装は public な no-arg コンストラクタ か public static provider() を持てばよい。

コンシューマ側は uses で「このサービスを使う」と宣言する。これが ServiceLoader.load(...) の前提になる。 そしてコンシューマはプロバイダ・モジュールを requires しない――それこそが「実装を知らずに差し替え可能」という疎結合の核心。

各誤答が違う理由
  • A実装クラスの exports は不要。provides … with … が登録を担い、生成はモジュールシステムが行う。exports は逆に実装を露出させる悪手。
  • Cコンシューマがプロバイダを requires したら、実装に直接依存してしまい疎結合の意味が消える。requires は不要(実際に無しで動く)。
  • Duses は必須。これが無いと ServiceLoader.load はサービスを発見できない(モジュールグラフ上の宣言が前提)。
ひっかけ: 「使うんだから実装モジュールを requires/実装を exports するのが当然」という非モジュール時代の感覚。サービスはrequires も exports も無しで、provides/with+uses だけで繋がる。これが SPI(Service Provider Interface)の旨味。
実機確認の答え合わせ
StripePayment を exports せず/com.shop は com.pay.stripe を requires せず、
provides/with+uses だけで構成 → java --module com.shop/...Main の出力:

stripe-paid

(=ServiceLoader がプロバイダを発見・生成できた。実装クラスは公開していない)
※ もし StripePayment に public 引数なしコンストラクタが無いと、生成時に ServiceConfigurationError になる。
✓有資格者(著者)による書き下ろし解説

有資格者(著者)が監修した問題は、すべて無料サンプルとして公開しています。買う前に、その全部を実際に解いて解説まで読めます。有料で追加される問題はAIが作成したもので、有資格者の監修は入っていません。

この問題集の作り方

  1. 問題と解説はAIが作成しています。有資格者(著者)が監修した問題は、無料サンプルとして公開している分だけです。有料で追加される問題に監修は入っていません。
  2. 各問に、公式ドキュメントの出典リンクを付けています。書いてあることは、出典に当たって確かめられます。
  3. 誤答の選択肢それぞれに、なぜ誤りなのかの理由を書いています。
  4. 解説に載せているコンパイル結果は、実際に javac を走らせた出力です。想定した挙動ではありません。
  5. 誤りを見つけたら報告できます。原則として無償で訂正・削除します。
  6. 各試験の運営団体とは無関係の非公式教材です。合格を保証するものではありません。
この分野をもっと解いて、得点源に
モジュール を含む問題を分野別に演習できます。
演習する →