0Pricing
Java Academy · レッスン

provides/uses によるサービス

サービスローダーで疎結合にします。

「provides/uses によるサービス」はCoddyKit上の無料Java Academyレッスンです。 これはレッスン3/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはJava Academy学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 Java Academyコースには全4レッスンが含まれています。

サービスによる疎結合

モジュールは、サービスローダーパターンを使うことで、互いの実装に依存せずに連携できます。

あるモジュールはサービスインターフェースをusesすると宣言し、別のモジュールは実装をprovidesすると宣言します。JVMがそれらを結び付けます。

3つの役割

サービスには3つの参加者がいます。

  • サービスインターフェース:契約を定義するもので、いずれかのモジュールに置かれる
  • プロバイダー:実装を提供するモジュール
  • コンシューマー:実行時に実装を読み込むモジュール

サービスインターフェース

まず契約を定義します。これは、プロバイダーとコンシューマーの両方が参照できるようにエクスポートされたパッケージに置く、通常のインターフェースです。

package com.example.spi;

public interface Codec {
    String name();
    byte[] encode(String input);
}

コンシューマーによるusesの宣言

コンシューマーモジュールは、インターフェースをusesすると宣言します。これにより、JPMSに対して、このモジュールがServiceLoaderを通じて実装を検索することを伝えます。

module com.example.app {
    requires com.example.spi;
    uses com.example.spi.Codec;
}

プロバイダーによるprovidesの宣言

プロバイダーモジュールは、provides ... with ...を使って、どのインターフェースを実装するかを宣言し、具象クラスを指定します。

module com.example.base64 {
    requires com.example.spi;
    provides com.example.spi.Codec
        with com.example.base64.Base64Codec;
}

プロバイダーの実装

実装クラスは通常のJavaクラスです。publicであり、publicな引数なしコンストラクターまたはpublicなstatic provider()メソッドのいずれかを備えている必要があります。

package com.example.base64;

import com.example.spi.Codec;
import java.util.Base64;

public class Base64Codec implements Codec {
    public String name() { return "base64"; }
    public byte[] encode(String input) {
        return Base64.getEncoder().encode(input.getBytes());
    }
}

ServiceLoaderによる読み込み

実行時にコンシューマーはServiceLoader.load(Codec.class)を使って利用可能なすべてのプロバイダーを取得し、それらを反復処理します。実装へのコンパイル時リンクは必要ありません。

import com.example.spi.Codec;
import java.util.ServiceLoader;

public class App {
    public static void main(String[] args) {
        ServiceLoader<Codec> loader = ServiceLoader.load(Codec.class);
        for (Codec codec : loader) {
            System.out.println("Found codec: " + codec.name());
        }
    }
}

この仕組みが強力な理由

コンシューマーがプロバイダークラスの名前を直接指定することはありません。新しいプロバイダーモジュールをモジュールパスに追加すれば、自動的に検出されます。

これにより、プラグインアーキテクチャと、依存関係をきれいに逆転させた設計が可能になります。

provider()ファクトリ

生成にロジックが必要な場合は、引数なしコンストラクターの代わりにpublicなstatic provider()メソッドを公開します。JPMSがそれを呼び出してインスタンスを取得します。

package com.example.base64;

import com.example.spi.Codec;

public class CodecFactory {
    public static Codec provider() {
        return new Base64Codec();
    }
}

複数のプロバイダー

複数のモジュールが、それぞれ同じインターフェースを提供できます。ServiceLoaderはそれらをすべて返すため、コンシューマーは名前、優先度、または機能に基づいて選択できます。

コンシューマーのコードに変更を加えずに、プロバイダーを追加または削除できます。

プロバイダーのストリーム処理

Java 9以降、ServiceLoaderにはstream()が用意されており、インスタンス化する前にフィルタリングできるProviderハンドルを生成します。生成にコストがかかる場合に便利です。

import com.example.spi.Codec;
import java.util.ServiceLoader;

public class App {
    public static void main(String[] args) {
        Codec chosen = ServiceLoader.load(Codec.class).stream()
            .map(ServiceLoader.Provider::get)
            .filter(c -> c.name().equals("base64"))
            .findFirst()
            .orElseThrow();
        System.out.println("Using: " + chosen.name());
    }
}

クイックチェック

それぞれの役割で使うディレクティブを思い出してください。

まとめ

モジュールのサービスパターンを学びました。

  • 3つの役割:サービスインターフェース、プロバイダー、コンシューマー
  • コンシューマー:uses、プロバイダー:provides ... with
  • 実装は実行時にServiceLoaderで読み込む
  • プロバイダーにはpublicな引数なしコンストラクターまたはstaticなprovider()が必要

次は、既存プロジェクトをモジュールへ移行します。

よくある質問

「provides/uses によるサービス」レッスンは無料ですか?

はい。「provides/uses によるサービス」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、Java Academyコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 Java Academyコースには全4レッスンが含まれています。

「provides/uses によるサービス」で何を学びますか?

サービスローダーで疎結合にします。 ブラウザで直接実行するハンズオンコードでJava Academyを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。

Java Academyを始めるのに経験は必要ですか?

事前経験は必要ありません。CoddyKitのJava Academyは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン3/4です。

「provides/uses によるサービス」レッスンにはどのくらい時間がかかりますか?

ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。

このJava Academyレッスンでコードを書いて実行できますか?

はい。すべてのJava Academyレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。

このコースのすべてのレッスン

  1. module-info.java
  2. requires と exports
  3. provides/uses によるサービス
  4. モジュールへの移行
← Java Academyに戻る