Upload page content

You can upload content for the page named below. If you change the page name, you can also upload content for another page. If the page name is empty, we derive the page name from the file name.

File to load page content from
Page name
Comment

Locked History Actions

guice/Manual/BestPractices/ModulesShouldBeFastAndSideEffectFree

モジュールは速く副作用の無いこと

コンフィギュレーションのための外部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);
  }