Guiceの親子Injectorについてメモ自分用

Guiceのスコープが不勉強であったため、少しメモ

以下git sample
https://github.com/KOBUO/sample-guice

``` Project.Tree
└─src
    ├─main
    │  ├─java
    │  │  └─sample
    │  │      └─guice
    │  │          │  Main.java
    │  │          │
    │  │          └─subpackage
    │  │              │  SampleExecutor.java
    │  │              │  SampleFactory.java
    │  │              │
    │  │              ├─singleton
    │  │              │      Hello.java
    │  │              │
    │  │              └─test
    │  │                  │  ITester.java
    │  │                  │  Test.java
    │  │                  │
    │  │                  └─impl
    │  │                          Sample1Tester.java
    │  │                          Sample2Tester.java
    │  │                          Sample3Tester.java

```

Mainで親injectorを生成
Hello(Singleton)をbind

``` Main.java
package sample.guice;

import com.google.inject.AbstractModule;
import com.google.inject.Guice;
import com.google.inject.Injector;
import sample.guice.subpackage.SampleExecutor;
import sample.guice.subpackage.singleton.Hello;

public class Main {
    public static void main(String[] args) {
        Injector injector = Guice.createInjector(new AbstractModule() {
            @Override
            protected void configure() {
                this.bind(Hello.class).toInstance(new Hello("World")); //①
            }
        });
        injector.getInstance(SampleExecutor.class).execute();
        System.exit(0);
    }
}
```

SampleFactoryで親injectorをコンストラクタinject
Injector#createChildInjectorで子injectorを生成


``` SampleFactory.java
package sample.guice.subpackage;

import com.google.inject.AbstractModule;
import com.google.inject.Inject;
import com.google.inject.Injector;
import sample.guice.subpackage.test.ITester;
import sample.guice.subpackage.test.Test;
import sample.guice.subpackage.test.impl.Sample1Tester;
import sample.guice.subpackage.test.impl.Sample2Tester;
import sample.guice.subpackage.test.impl.Sample3Tester;

public class SampleFactory {

    private final Injector _injector;

    @Inject
    public SampleFactory(Injector injector) {
        this._injector = injector;
    }

    ITester getTester(Test test) {

        Injector injector = this._injector.createChildInjector(new AbstractModule() {
            @Override
            protected void configure() {
                bind(Hello.class).toInstance(new Hello("SubWorld")); //②
            }
        });

        switch (test) {
            case SAMPLE1:
                return injector.getInstance(Sample1Tester.class);
            case SAMPLE2:
                return injector.getInstance(Sample2Tester.class);
            case SAMPLE3:
                return injector.getInstance(Sample3Tester.class);
            default:
                throw new IllegalArgumentException();
        }
    }
}
```

HelloでSingletonアノテーションを付与

``` Hello.java
package sample.guice.subpackage.singleton;

import javax.inject.Singleton;

@Singleton
public class Hello {

    private final String _name;

    public Hello(String name){
        System.out.println("constructor is Hello");
        this._name = name;
    }

    public void message(){
        System.out.println(String.format("Hello %s", this._name));
    }
}
```

実行すると以下のメッセージが。
HelloのインスタンスはMainでもう生成している旨出力
親injectorが子に受け継がれていることがわかる

``` Terminal.log
Exception in thread "main" com.google.inject.CreationException: Unable to create injector, see the following errors:

1) A binding to sample.guice.subpackage.singleton.Hello was already configured at sample.guice.Main$1.configure(Main.java:14).
  at sample.guice.subpackage.SampleFactory$1.configure(SampleFactory.java:27)

1 error
	at com.google.inject.internal.Errors.throwCreationExceptionIfErrorsExist(Errors.java:543)
	at com.google.inject.internal.InternalInjectorCreator.initializeStatically(InternalInjectorCreator.java:159)
	at com.google.inject.internal.InternalInjectorCreator.build(InternalInjectorCreator.java:106)
	at com.google.inject.internal.InjectorImpl.createChildInjector(InjectorImpl.java:237)
	at com.google.inject.internal.InjectorImpl.createChildInjector(InjectorImpl.java:242)
	at sample.guice.subpackage.SampleFactory.getTester(SampleFactory.java:24)
	at java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:193)
	at java.util.Spliterators$ArraySpliterator.forEachRemaining(Spliterators.java:948)
	at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:481)
	at java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:471)
	at java.util.stream.ForEachOps$ForEachOp.evaluateSequential(ForEachOps.java:151)
	at java.util.stream.ForEachOps$ForEachOp$OfRef.evaluateSequential(ForEachOps.java:174)
	at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
	at java.util.stream.ReferencePipeline.forEach(ReferencePipeline.java:418)
	at sample.guice.subpackage.SampleExecutor.execute(SampleExecutor.java:19)
	at sample.guice.Main.main(Main.java:17)
```

Mainのbind(Hello)をコメントアウトすると
子のスコープでシングルトンであるため、３回コンストラクタが呼ばれる。

``` Terminal.log
> Task :Main.main()
constructor is Hello
Hello SubWorld
constructor is Hello
Hello SubWorld
constructor is Hello
Hello SubWorld
```

SampleFactoryのbind(Hello)をコメントアウトすると
親のスコープでシングルトンであるため、１回コンストラクタが呼ばれる。

```
> Task :Main.main()
constructor is Hello
Hello World
Hello World
Hello World
```