[Seasar-user:19585] Re: 【ご質問】S2ContainerのDI対象クラスインスタンス生成について

Koichi Kobayashi [E-MAIL ADDRESS DELETED]
2010年 4月 1日 (木) 20:00:00 JST


小林 (koichik) です.

Date:    Thu, 1 Apr 2010 12:49:15 +0900
From:    [E-MAIL ADDRESS DELETED]
To:      [E-MAIL ADDRESS DELETED]
Subject: [Seasar-user:19584] 【ご質問】S2ContainerのDI対象クラスインスタンス生成について

> 質問:DI対象クラスをprototypeで指定し、同じcomponentを2回取得する場合、2
> 回目はインスタンス生成した後、取得する
>     と書籍等に記載されておりますが、ソース上で具体的にどこで実装されて
> いるのでしょうか?

prototype の場合,1 回目も 2 回目も
インスタンスを生成して返します.
該当するコードは

org.seasar.framework.container.deployer.PrototypeComponentDeployer

です.
コンポーネントのライフサイクルに関しては
deployer パッケージ,DI に関しては
assembler パッケージが中心になります.

>         2.DIコンテナ生成(対象メソッドinit)
>                 XML解析→DIコンテナ生成→初回キャッシュ
>                 SingletonS2ContainerFactory.init();

「初回キャッシュ」というか,
SingletonS2ContainerFactory は S2 コンテナを
シングルトン (厳密には違いますが,どこからでも
同じコンテナを取得できるという意味) として扱う
クラスです.

>                 ・初回キャッシュは
>                         
> org.seasar.framework.container.factory.ComponentTagHandlerクラスのstart(
> )メソッドで
>                         componentClass = ClassUtil.forName(className)を用
> い、インスタンス生成しています。

ここではクラスを取得しているだけで,
インスタンスは生成していません.

singleton の場合は,この後
S2ContainerImpl#init() → ComponentDefImpl#init()
→ SingletonComponentDeployer#init() で
インスタンスが生成されます.

>         3.コンポーネント取得(1回目)(対象メソッドgetComponet)
>         4.コンポーネント取得(2回目)(対象メソッドgetComponet)

1 回目と 2 回目で違いはありません.
prototype の場合はいずれの場合も前述の
PrototypeComponentDeployer でインスタンスが
生成されます.

> 3のコンポーネント取得の場合、DIコンテナへキャッシュしたものを取り出すと思
> うのですが、4の動き(2回目のコンポーネントのインスタンス化)
> をまだ把握出来ておりません。

prototype はキャッシュしません.
っていうか,コンポーネントの管理については
「キャッシュ」という表現は不適切だと思います.
singleton なら唯一のインスタンスを保持しますが
(SingletonComponentDeployer 参照),それが
本質的なものであってキャッシュというわけでは
ありません.

「初回キャッシュ」という用語が連発されて
いますが,コンポーネントのインスタンスに
関してはキャッシュはしていないと考えてください.
リフレクションに関する情報などはキャッシュして
いますが.

文面からは,コンテナとコンポーネント,
クラスとインスタンスが混同されているように
見えます.
これらの区別を意識するようにするといいのでは
ないかと思います.

S2Container の動作を理解するなら,
Factory から追いかけるより,以下のように
コンテナを組み立てる方が簡単ではないかと
思います.

public void test() throws Exception {
  S2ContainerImpl container = new S2ContainerImpl();

  ComponentDefImpl cd1 = new ComponentDefImpl(Foo.class, "foo");
  container.register(cd1);

  ComponentDefImpl cd2 = new ComponentDefImpl(Bar.class, "bar");
  cd2.setInstanceDef(InstanceDefFactory.PROTOTYPE);
  container.register(cd2);

  container.init();

  Foo foo1 = (Foo) container.getComponent(Foo.class);
  Foo foo2 = (Foo) container.getComponent(Foo.class);
  assertSame(foo1, foo2);

  Bar bar1 = (Bar) container.getComponent(Bar.class);
  Bar bar2 = (Bar) container.getComponent(Bar.class);
  assertNotSame(bar1, bar2);
}

singleton のコンポーネント (Foo) は,
前述したように container.init() の際に
インスタンスが生成されますが,prototype の
コンポーネント (Bar) はその時点では
インスタンス化されず,getComponent() の
度にインスタンス化されます.


-- 
<component name="koichik">
    <property name="fullName">"Koichi Kobayashi"</property>
    <property name="email">"[E-MAIL ADDRESS DELETED]"</property>
    <property name="blog">"http://d.hatena.ne.jp/koichik"</property>
</component>



Seasar-user メーリングリストの案内