スコープの短いコンポーネントの取得
暇つぶしネタ。
S2 などの DI コンテナを使っていると、sintleton コンポーネントから prototype などの、よりスコープの短いコンポーネントを取得したいケースがあります。
この場合、単純に DI するだけではうまくいきません。
public interface BarService { void execute(); } public class FooServiceImpl implements FooService { private BarService service; // prototype-scope public void setBarService(BarService service) { this.service = service } public void fooMethod() { service.execute(); } }
上記のように FooService を DI してしまうと、BarService はコンテナ起動時に1回だけ初期化されるため、そのときに FooService の DI が行われてしまい、毎回新しい service インスタンスがほしい場合にはうまくいきません。
この問題は通常、 S2Container からコンポーネントを直接取ることで解決します。
public class FooServiceImpl implements FooService { public void fooMethod() { FooService service = (FooService) SingletonS2ContainerFactory.getContainer().getComponent(BarServiceImpl.class); service.execute(); } }
prototype スコープであれば、getComponent するたびにコンポーネントが生成されますので、これで問題は解決です。
・・・が、少し記述が長ったらしくなってしまうので、ユーティリティメソッドを作ってみました。
public class Components { @SuppressWarnings("unchecked") public static <T> T get(Class<? extends T> clazz) { return (T) SingletonS2ContainerFactory.getContainer().getComponent(clazz); } } public class FooServiceImpl implements FooService { void fooMethod() { BarService service = Components.get(BarServiceImpl.class); service.execute(); } }
だいぶすっきりしました。
なお Eclipse ecjではコンパイルが通り実行できましたが、javac でコンパイルが通るかは未確認です。