サービスと言っても、今回やろうとしているのはWebサービスとかではなくJavaが備えているモジュール切り替えの仕組み。
例えば、JDBCドライバは様々なDBMSに対応しているけど、インターフェースに従ってさえいれば、切り替えは比較的容易になっている。
サービスは実装を伴わず、インターフェースを定義する。
サービスプロバイダーはサービスを実装する。
アプリケーションはサービスを通じてサービスプロバイダーを呼び出す。
この3つをそれぞれ別のjarにして、呼び出してみよう。
local/api/MyService.java
local/provider/MyServiceProvider1.java
jarを作る前にMETA-INF/services/にMyServiceを実装したサービスプロバイダーとして公開するクラスを記載しておく必要がある。
META-INF/services/local.api.MyService
サービスを呼び出すためにはjava.util.ServiceLoaderを使って、特定のサービスインターフェースを実装したサービスプロバイダーを探す必要がある。
local/app/Main.java
例えば、JDBCドライバは様々なDBMSに対応しているけど、インターフェースに従ってさえいれば、切り替えは比較的容易になっている。
登場人物
登場人物はサービス、サービスプロバイダー、アプリケーションの3つ。サービスは実装を伴わず、インターフェースを定義する。
サービスプロバイダーはサービスを実装する。
アプリケーションはサービスを通じてサービスプロバイダーを呼び出す。
この3つをそれぞれ別のjarにして、呼び出してみよう。
サービス
まずはサービスのインターフェースを定義する。local/api/MyService.java
package local.api; public interface MyService { void show(); }これをコンパイルしてjarにする。
$ javac -d bin src/local/api/*.java $ jar cvf local-api.jar -C bin .
サービスプロバイダー
次にサービスプロバイダー。試しに2つ作ってみる。local/provider/MyServiceProvider1.java
package local.provider; import local.api.MyService; public class MyServiceProvider1 implements MyService { @Override public void show() { System.out.println("MyService1"); }; }local/provider/MyServiceProvider2.java
package local.provider; import local.api.MyService; public class MyServiceProvider2 implements MyService { @Override public void show() { System.out.println("MyService2"); }; }先ほど作ったlocal-api.jarを参照してコンパイル。
$ javac -d bin -cp .:../api/local-api.jar src/local/provider/*.java
jarを作る前にMETA-INF/services/にMyServiceを実装したサービスプロバイダーとして公開するクラスを記載しておく必要がある。
META-INF/services/local.api.MyService
local.provider.MyServiceProvider1 local.provider.MyServiceProvider2
$ jar cvf local-provider.jar -C bin .
アプリケーション
最後にサービスプロバイダーを実行するアプリケーションを作成する。サービスを呼び出すためにはjava.util.ServiceLoaderを使って、特定のサービスインターフェースを実装したサービスプロバイダーを探す必要がある。
local/app/Main.java
package local.app; import java.util.ServiceLoader; import local.api.MyService; public class Main { public static void main(String ... args) { for (MyService service : ServiceLoader.load(MyService.class)) { System.out.println(service.getClass().getName()); service.show(); } } }
$ javac -d bin -cp .:../api/local-api.jar src/local/app/*.java $ jar cvf local-app.jar -C bin .
実行
すべてのjarができたので、実行してみよう。jarをlibに集めておく。$ ls lib local-api.jar local-app.jar local-provider.jar $ java -cp ./lib/local-app.jar:./lib/local-api.jar:./lib/local-provider.jar local.app.Main local.provider.MyServiceProvider1 MyService1 local.provider.MyServiceProvider2 MyService2
全体のディレクトリイメージ
$ tree . ├── api │ ├── bin │ │ └── local │ │ └── api │ │ └── MyService.class │ ├── local-api.jar │ └── src │ └── local │ └── api │ └── MyService.java ├── app │ ├── bin │ │ └── local │ │ └── app │ │ └── Main.class │ ├── local-app.jar │ └── src │ └── local │ └── app │ └── Main.java ├── lib │ ├── local-api.jar │ ├── local-app.jar │ └── local-provider.jar └── provider ├── bin │ ├── META-INF │ │ └── services │ │ └── local.api.MyService │ └── local │ └── provider │ ├── MyServiceProvider1.class │ └── MyServiceProvider2.class ├── local-provider.jar └── src └── local └── provider ├── MyServiceProvider1.java └── MyServiceProvider2.java
0 件のコメント:
コメントを投稿