Stage-Injectionするタイミングを変更する

Singletonの初期化タイミングの制御、Stageについて

今までInjectorを作るのにGuice.createInjector(new OkinawaModule());で作っていましたが更にStageを指定する事が可能です。

Guice.createInjector(Stage.DEVELOPMENT, new OkinawaModule());
// または //
Guice.createInjector(Stage.PRODUCTION, new OkinawaModule());

あとStage.TOOLというのもありますが、これはInjectionをしないモードなのでここでは扱いません。

DEVELOPMENTでは Startup時間を早くするように動作し、PRODUCTIONではStartup時間は長くなるけどPerformanceが良くなる様に動作

以下のように書き換えてServiceImplが作成されたタイミングでメッセージを出力してみる

import com.google.inject.Singleton;

@Singleton
public class ServiceImpl implements Service {
  
    public ServiceImpl() {
        System.out.println("Created ServiceImpl instance.");
    }

    @Override
    public String getResponse(String message) {
        return "ハイサイ!" + message;
    }
  
}

Stageを PRODUCTIONにします。

import com.google.inject.Guice;
import com.google.inject.Injector;
import com.google.inject.Stage;

public class Main {

    public static void main(String[] args) {
        System.out.println(“Create Injector…”);
        Injector injector = Guice.createInjector(Stage.PRODUCTION, new OkinawaModule());
        System.out.println(“done.”);
        Client client1 = injector.getInstance(Client.class);
        Client client2 = injector.getInstance(Client.class);
        // 実行する。
        client1.execute();
        client2.execute();
        // service の instanceはどうなった?
        if (client1.getService() == client2.getService()) {
            System.out.println(“Service is singleton.”);
        } else {
            System.out.println(“Service is NOT singleton.”);
        }
    }
}

これで実行してみます。Stage.PRODUCTIONです。

>java -cp di.jar;. Main
Created ServiceImpl instance.
Injector is created.
Create instance 1
Create instance 2
ハイサイ!Guice1
ハイサイ!Guice2
Service is singleton.

DEVELOPMENTステージに変更して実行します。

Injector is created.
Create instance 1
Created ServiceImpl instance.
Create instance 2
ハイサイGuice1
ハイサイGuice2
Service is singleton.

ServiceImplのインスタンスが作成されたタイミングが変わったのが分かるかと思います。GuiceではSingletonの初期化方法が二種類あってそれぞれタイミングが違うために起こります。

この二種類のSingleton(の初期化)は Eager Singleton と Lazy Singletonと呼ばれています。

要求されるまでオブジェクトを作らないLazyと要求される前に予め作っておくEagerという事です。

DEVELOPMENT Stageでは出来るだけ Lazyにして開始時間を短縮し(これによりCompile→Runという流れを速くします)、PRODUCTIONでは Eagerで作成しておいて利用される場面で高速に動作するように動きます。

Stage.DEVELOPMENTでも事前作成にしたい Singletonがある場合はbindする時に.asEagerSingleton()とする事で事前に作る事が可能です。

bind(Service.class).to(ServiceImpl.class).asEagerSingleton();

これでDEVELOPMENT StageでもInjectorが作成されたタイミングでSingletonが作成されます。