今更EOLしたSeasar2かよって言われそうですが、次のプロジェクトで使う予定なので勉強してみる。
ALL in ONE Eclipseの4.7あたりだとまともにDoltengプラグインとか動かないのが辛い(Javaのバージョン下げたりとかすればなんとかプロジェクト作れるけどその後の動きも結構怪しい)ので、3.7使ってます・・・。
作ったもの
app.dicon
<component name="messageTarget"
class="s2.sample.s2comtainer.helloworld.DefaultMessageTarget"
instance="singleton">
</component>
<component name="messageProvider"
class="s2.sample.s2comtainer.helloworld.HelloMessageProvider"
instance="singleton">
</component>
これ以外の とかは一旦コメントアウトした。
どのクラスをどこのコンポーネント名で登録するかを定義してる感じなのでSpringやってればなるほどねってなる設定ファイル。
DefaultMessageTarget.javaはIMessageTargetっていうgetNameメソッドだけ定義しているIFの実装クラス。
public class DefaultMessageTarget implements IMessageTarget{
@Override
public String getName() {
return "World";
}
}
IMessageProviderは以下のようなIF
public interface IMessageProvider {
public void setMessageTarget(IMessageTarget messageTarget);
public String getMessage();
}
それの実装がこれ
public class HelloMessageProvider implements IMessageProvider {
private IMessageTarget messageTarget;
@Override
public void setMessageTarget(IMessageTarget messageTarget) {
this.messageTarget = messageTarget;
}
@Override
public String getMessage() {
return "Hello, " + messageTarget.getName() + "!";
}
}
で、これらを呼ぶとこうなる
// S2コンテナの初期化
SingletonS2ContainerFactory.init();
// IMessageProviderIFを実装したコンポーネントを取得
IMessageProvider messageProvider = SingletonS2Container.getComponent(IMessageProvider.class);
// メッセージを出力(Hello, World!って出る)
System.out.println(messageProvider.getMessage());
// S2コンテナの破棄
SingletonS2ContainerFactory.destroy();
SingletonS2Container.getComponent(IMessageProvider.class)のところで、IMessageProviderっていうクラス(IF)を指定しているが
これの実装はHelloMessageProviderしか居ないのでHelloMessageProviderが生成される。
で、HelloMessageProviderが生成される時にsetterインジェクションが走って
IMessageTargetの唯一の実装であるDefaultMessageTargetが注入された状態のHelloMessageProviderが受け取れるってところですかね。
ちなみにHelloMessageProviderの
private IMessageTarget messageTarget;としている変数名をmessageTarget3ってしても動くし、
セッターメソッドをsetMessageTarget3みたいにしても動く。
ただし、app.diconの設定ファイルを変えて
SeasarMessageTargetというIMessageTargetの実装クラスをもう一個追加してやるとどうなるかというと
<component name="messageTarget"
class="s2.sample.s2comtainer.helloworld.DefaultMessageTarget"
instance="singleton">
</component>
<component name="messageTarget2"
class="s2.sample.s2comtainer.helloworld.SeasarMessageTarget"
instance="singleton">
</component>
<component name="messageProvider"
class="s2.sample.s2comtainer.helloworld.HelloMessageProvider"
instance="singleton">
</component>
setMessageTargetというセッターインジェクション名だとDefaultMessageTargetがインジェクションされる。
setMessageTarget2というセッターインジェクション名だとSeasarMessageTargetがインジェクションされる。
setMessageTarget3というセッターインジェクション名だと以下のようなエラーになる。
Exception in thread "main" org.seasar.framework.beans.IllegalPropertyRuntimeException: [ESSR0059]クラス(s2.sample.s2comtainer.helloworld.HelloMessageProvider)のプロパティ(messageTarget3)の設定に失敗しました。理由はorg.seasar.framework.container.TooManyRegistrationRuntimeException: [ESSR0045]interface s2.sample.s2comtainer.helloworld.IMessageTargetに複数のコンポーネント(s2.sample.s2comtainer.helloworld.DefaultMessageTarget, s2.sample.s2comtainer.helloworld.SeasarMessageTarget)が登録されています
という結果になった。
なので、セッターのメソッド名のsetXXXの部分がcomponent nameと合っていればそれを優先、
あっていなくてもIFを実装したクラスが一個なら宜しく注入する。ただし複数ある場合は名前から判別できない場合はどれをセットしていいか分からないからエラーになると言ったところか。