Container の組み立て
難しいところは省略していくよー。 S2ContainerFactory#createからProvider#build を呼び出す。お、S2ContainerBuilder という如何にもな名前のインターフェースを発見。SingletonS2ContainerFactory#init で、設定した configPath の dicon ファイルを解析します。実態は XmlS2ContainerBuilder で、 TagHandlerContext にパースした dicon のコンテキスト情報(つまり, S2Container!)を保持します。AbstractTagHandler が SAX で解析するときのハンドラで、複数のタグに対応しています。例えば以下のクラスが存在します。例えばアスペクトってどうやって織り込まれてるの?って確認したいときは, AspectTagHandler から読み進めると良いんじゃないかと思います。アスペクトに関しては後日読もうかと思っています。
- ArgTagHandler
- AspectTagHandler
- ComponentsTagHandler
- ComponentTagHandler
- IncludeTagHandler
- InterTypeTagHandler
- MetaTagHandler
- MethodTagHandler
- PropertyTagHandler
Seasar の dicon ファイルでは Components がルートタグになっている(と思う・・・調べてない)ので, まず ComponentsTagHandler で Container を生成します。実際のコンテナの実装クラスは書いていませんが、ここが Container の生まれる場所ですね。勿論, 親のコンテナがあれば親もセットされます。
protected S2Container createContainer() { return (S2Container) ClassUtil.newInstance(containerImplClass); }
次に, ComponentTagHandler で順次コンポーネント定義をコンテキストに push していきます。今回は面倒なので ComponentTagHandler のみ見てみます。取り敢えず大事そうなところだけ抽出してみましょう。タグの開始に対するコールバックとして, コンテキストに ComponentDef を push します。
public void start(TagHandlerContext context, Attributes attributes) { String className = attributes.getValue("class"); Class componentClass = null; if (className != null) { componentClass = ClassUtil.forName(className); } String name = attributes.getValue("name"); ComponentDef componentDef = createComponentDef(componentClass, name); String instanceMode = attributes.getValue("instance"); if (instanceMode != null) { componentDef.setInstanceDef(InstanceDefFactory .getInstanceDef(instanceMode)); } String autoBindingName = attributes.getValue("autoBinding"); if (autoBindingName != null) { componentDef.setAutoBindingDef(AutoBindingDefFactory .getAutoBindingDef(autoBindingName)); } context.push(componentDef); }
タグが終了したら, コンポーネント定義を S2Container に登録します。ここでようやく S2Container#register が登場しました。式の解析なども行われているようですが、特に興味も無いので飛ばします。
public void end(TagHandlerContext context, String body) { ComponentDef componentDef = (ComponentDef) context.pop(); String expression = null; if (body != null) { expression = body.trim(); if (!StringUtil.isEmpty(expression)) { componentDef .setExpression(createExpression(context, expression)); } else { expression = null; } } if (context.peek() instanceof S2Container) { S2Container container = (S2Container) context.peek(); container.register(componentDef); } else { ArgDef argDef = (ArgDef) context.peek(); argDef.setChildComponentDef(componentDef); } }
S2Container で登録された ComponentDef は, S2ContainerImpl#componentDefMap に保持されます。次はここからどのように ComponentDef を読み込み、クラスを生成してインジェクションされるか見てみましょう。