モジュール(サービス 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 で正しく発見・生成されるための要件として正しいものを選べ。
- A
com.pay.stripeは実装クラスStripePaymentをexportsしなければならない(さもないとServiceLoaderが見つけられない)。 - B
StripePaymentが public で、public な引数なしコンストラクタ(または public static なprovider()メソッド)を持てばよい。実装クラスをexportsする必要はない。 - C
com.shopのmodule-infoにrequires com.pay.stripe;も追加しないとプロバイダを発見できない。 - D
uses宣言は不要。ServiceLoader.loadはusesなしでも全モジュールを走査して自動発見する。
正解・解説・誤答理由・ひっかけを見る▼ open
✓ 正解:B✓Gold監修
解説
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は不要(実際に無しで動く)。 - D
usesは必須。これが無いと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 になる。
公式ドキュメント・関連java.util.ServiceLoader(API ドキュメント・Deploying / provider 要件)↗JLS SE21 §7.7.4 Service Consumption(uses)↗
✓Gold 保有者による書き下ろし解説・実機で検証済