モジュールは速く副作用の無いこと
コンフィギュレーションのための外部XMLではなく、Guiceでは通常のJavaコードを使ってモジュールを記述する。 Javaならわかりやすく、IDEで操作可能で、リファクタリングしてもおかしくならない。
しかし、Java言語のフルパワーを生かすにはコストがかかる。モジュール内で「やりすぎ」がたやすくできてしまう。 モジュール内でHTTPサーバを開始しデータベースに接続するというような誘惑にかられる。 こんなことをしないように! 重量級のモジュールでは問題が発生しかねない。
- モジュールがスタートアップするが、シャットダウンしない。モジュール内でデータベース接続を開始するとそれをクローズする方法がない。
- モジュールをテストしなければならなくなる。モジュール内でデータベース接続をオープンすると、それをテストするのは難しい。
- モジュールはオーバライド可能である。Guiceモジュールはオーバライドをサポートしており、製品向けサービスを軽いテスト用のものに代替することが可能であるが、製品サービスをモジュール実行の一部として起動してしまうと、そのようなオーバライドが意味をなさなくなる。
モジュール自体の中でそのような仕事をさせるのではなく、特定の抽象の中でそのような仕事ができるようなインターフェースを定義すべきである。 例えばこのように。
public interface Service {
/**
* サービスをスタートする。このメソッドはサービスが完全に開始するまでブロックする。
*/
void start() throws Exception;
/**
* サービスを停止する。完全にシャットダウンするまでブロックする。
*/
void stop();
}インジェクタを作成した後は、そのサービスを開始することでアプリのブートストラップを終了する。 アプリをストップさせるときは、リソースを完全に解放するためのシャットダウンフックも提供する。
public static void main(String[] args) throws Exception {
Injector injector = Guice.createInjector(
new DatabaseModule(),
new WebserverModule(),
...
);
Service databaseConnectionPool = injector.getInstance(
Key.get(Service.class, DatabaseService.class));
databaseConnectionPool.start();
addShutdownHook(databaseConnectionPool);
Service webserver = injector.getInstance(
Key.get(Service.class, WebserverService.class));
webserver.start();
addShutdownHook(webserver);
}