Seasar DI Container with AOP
S2Container.NET TOPページへ

S2Container.NET リファレンス

作成すべきファイル

S2Containerを使用するためには、定義ファイルを作成する必要があります。
定義ファイルは、コンポーネントを組み立てるための設計書のようなものです。
形式はXMLで、拡張子は、diconです。(xmlでも特に問題はありません)diconは、ダイコンと読みます。

S2Containerの定義

S2Containerの定義は、次のようになります。

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE components PUBLIC "-//SEASAR2.1//DTD S2Container//EN"
"http://www.seasar.org/dtd/components21.dtd">
<components>
    <component name="..." class="...">

            ...
    </component>
    <component name="..." class="...">
            ...
    </component>
</components>

DOCTYPEは省略できません。diconファイルを作成する場合は、上記のサンプルをコピー&ペーストしてください。ルートはcomponentsタグです。コンポーネントごとに、componentタグを定義していきます。componentタグのclass属性でコンポーネントのクラスの完全限定名を指定します。name属性には、コンポーネント名を指定します。詳細は、S2Container定義タグリファレンスを参照してください。

<components>
    <component name="hoge" class="Seasar.Examples.Dicon.HogeImpl"/>

</components>

S2Containerの生成と定義ファイル(Diconファイル)

S2Containerを作成する場合は、次のメソッドを使用します。

- Seasar.Framework.Container.Factory.S2ContainerFactory#Create(string path)

定義ファイルは、埋め込まれたリソースもしくはファイルシステムで指定することができます。 ※Visual Studio 2005のWebサイトプロジェクトでは埋め込まれたリソースにすることが出来ないので、 ファイルシステムを使用するか別のクラスライブラリプロジェクト等を作成して、そこに埋め込む必要があります。

埋め込まれたリソースを使用する場合は、引数pathは定義ファイルの名前空間を含む完全限定名です。 セパレータは、[ / ](スラッシュ)もしくは[ . ](ピリオド)です。 定義ファイルのビルドアクションプロパティは、埋め込まれたりソースに設定します。

C#プロジェクトの場合は、フォルダを作成すると名前空間が作成されます。 VB.NETプロジェクトの場合は、フォルダを作成しても名前空間は作成されません。 例えば、プロジェクトフォルダ/Sample/Logic/aaa.diconとすると、C#プロジェクトの場合は、 既定の名前空間/Sample/Logic/aaa.diconになります。 VB.NETの場合は、既定の名前空間/aaa.diconになります。

ファイルシステムを使用する場合は、一般的なファイルパスを指定します。 絶対パス、相対パスを指定できます。

埋め込まれたリソース、ファイルシステムの定義ファイルを混在させることもできます。 同じパスで埋め込まれたリソース、ファイルシステムの両方でヒットする場合は、 ファイルシステムの定義ファイルが優先されます。


private const string PATH = "aaa/bbb/ccc.dicon";
...
IS2Container container = S2ContainerFactory.Create(PATH);

コンポーネントの取得

S2Containerからコンポーネントを取り出すには、次のメソッドを使用します。

- Seasar.Framework.Container.IS2Container#GetComponent(object componentKey)

引数には、コンポーネントの型宣言を表すSystem.Typeもしくはコンポーネント名を指定できます。 詳しくは、componentタグを参照してください。 コンポーネントのクラスを指定する場合、コンポーネント is クラスがtrueを返すクラスなら 指定することができます。しかし、S2Containerの中に指定したクラスを実装しているコンポーネントが複数ある場合、 S2Containerは、どのコンポーネントを返せばよいのか判断できないため、 TooManyRegistrationRuntimeExceptionが発生します。 実装コンポーネントがユニークに決まるクラスを指定してください。 コンポーネント名で取得することもできます。その場合も、同一の名前をもつコンポーネントが複数登録されている場合、 TooManyRegistrationRuntimeExceptionが発生します。コンポーネント名指定の場合、 スペルミスをする可能性もあるので、できるだけクラス指定のほうが良いでしょう。

例) クラスを指定してコンポーネントを取得する場合

IS2Container container = S2ContainerFactory.Create(PATH);
Hoge hoge = (Hoge) container.GetComponent(typeof(Hoge));

例) コンポーネント名を指定してコンポーネントを取得する場合

IS2Container container = S2ContainerFactory.Create(PATH);
Hoge hoge = (Hoge) container.GetComponent("hoge");

アプリケーション構成ファイル

アプリケーション構成ファイル(※diconファイルではありません)に<seasar>構成セクションを追加することができます。 <seasar>構成セクションでは、ルートとなる定義ファイル(diconファイル)、 S2Container作成時にロードするアセンブリを指定することができます。

指定された定義ファイルは、Seasar.Framework.Container.Factory.SingletonS2ContainerFactory#Init が呼び出されたときに、ルートの定義ファイルとしてセットされます。

指定されたアセンブリは、Seasar.Framework.Container.Factory.S2ContainerFactory#Create が呼び出されたときに、アプリケーションドメインに読み込まれます。

diconファイルに登録したクラスが見つからずにClassNotFoundRuntimeExceptionが発生する場合は、 <assemblys>にアセンブリを指定することを忘れていないか確認してみてください。

<configuration>
   <configSections>
      <section name="seasar"
         type="Seasar.Framework.Xml.S2SectionHandler, Seasar" />
   </configSections>

   <seasar>
      <!-- SingletonS2ContainerFactory#Initで下記で指定されたdiconファイルを
           ルートのdiconファイルの初期値としてセットします。 -->
      <configPath>App.dicon</configPath>
      
      <!-- S2コンテナ作成時に以下で指定されたアセンブリをAppDomainに
           読み込みます。(S2ContainerFactory#Create) -->
      <assemblys>
         <assembly>アセンブリ名1</assembly>
         <assembly>アセンブリ名2</assembly>
      </assemblys>
   </seasar>

</configuration>

Dependency Injectionのタイプ

Dependency Injectionには、コンポーネントの構成に必要な値をコンストラクタで設定する (Constructor Injection)のか、プロパティのsetアクセサで設定する(Property Injection)のか、 初期化メソッドで設定する(Method Injection)のかで、タイプが分かれます。 Method InjectionはS2のオリジナルです。(S2Container.NETでもサポート) S2Container.NETはすべてのタイプとそのハイブリッド型もサポートします。

コンストラクタ・インジェクション

コンストラクタ・インジェクションとは、任意のコンストラクタの引数値にDependency Injectionします。
S2Containerの定義ファイルには、次の内容を記述します。

  • コンポーネントの指定
    コンポーネントは、componentタグで組み立てます。 class属性でクラス名を指定します。
    name属性でコンポーネントに名前を付けることもできます。
  • コンストラクタの引数の指定
    コンポーネントのコンストラクタの引数は、 componentタグの子タグであるargタグを使って指定します。
    文字列の場合は、 ダブルコーテーション(")で囲みます。
<components>
    <component name="..." class="...">

          <arg>...</arg>
    </component>
</components>
詳しい使用方法は、Exampleのコンストラクタ・インジェクションを参照してください。

プロパティ・インジェクション

プロパティ・インジェクションとは、任意のプロパティにsetアクセサを使用してProperty Injectionします。
S2Containerの定義ファイルには、次の内容を記述します。

  • コンポーネントの指定
    コンポーネントの指定は、コンストラクタ・インジェクションと同様です。
    name属性でコンポーネントに名前を付けることもできます。
  • プロパティの指定
    コンポーネントのプロパティは、componentタグの子タグであるpropertyタグを使って指定します。
    name属性でプロパティ名を指定します。
<components>
    <component name="..." class="...">
          <property name="...">...</property>

    </component>
</components>
詳しい使用方法は、Exampleのプロパティ・インジェクションを参照してください。

メソッド・インジェクション

メソッド・インジェクションとは、任意のメソッドを呼び出して、Dependency Injectionします。
S2Containerの定義ファイルには、次の内容を記述します。

  • コンポーネントの指定
    コンポーネントの指定は、コンストラクタ・インジェクションと同様です。
    name属性でコンポーネントに名前を付けることもできます。
  • 初期化メソッドの指定
    initMethodタグを使って、コンポーネントの任意のメソッドを呼び出します。 name属性で、メソッド名を指定します。引数は、argタグを子タグに使います。name属性を省略して、 ボディで、JScript.NETを使うこともできます。 その際、コンポーネント自身はselfで表します。
<components>
    <component name="..." class="...">
          <initMethod>...</initMethod>

    </component>
</components>
詳しい使用方法は、Exampleのメソッド・インジェクションを参照してください。

S2Container定義の分割とインクルード

すべてのコンポーネントを1つのファイルに記述すると、直ぐに肥大化してしまい管理が難しくなります。そのため、コンポーネントの定義を複数に分割する機能と分割された定義をインクルードして1つにまとめる機能がS2Containerにあります。S2Container定義ファイルのインクルードは次のようにして行います。

<components>
    <include path="bar.dicon"/>
</components>

includeタグのpath属性で取り込みたいS2Container定義ファイルのパスを指定します。詳しくは、includeタグを参照してください。
コンポーネントの検索順は、先ず自分自身に登録されているコンポーネントを探して、見つからない場合は、includeされている順に子供のS2Containerに登録されているコンポーネントを検索し、最初に見つかったコンポーネントが返されます。
次のような場合は、Foo(自身のコンポーネント)→aaa(子供のS2Container)→bbb(子供のS2Container)の順に検索します。

<components>
    <include path="aaa.dicon"/>
    <include path="bbb.dicon"/>
    <component class="Examples.Container.Foo" />

</components>

自動でコンストラクタ・インジェクションプロパティ・インジェクションを行う場合、S2Containerはインクルード先のコンポーネントを自動インジェクションすることができます。自動でDependency Injectionを行う場合の条件は自動バインディングを参照してください。
次のようにセッター・インジェクションでプロパティに指定するコンポーネントがインクルード先のaaa.diconとbbb.diconに登録されている場合、各HelloClientでは、どちらのコンポーネントが使用されるかをみてましょう。

root.dicon
<components>
    <include path="Seasar.Examples/Reference/Includes/aaa.dicon"/>
    <include path="Seasar.Examples/Reference/Includes/bbb.dicon"/>
    
    <component name="root" class="Seasar.Examples.Reference.Includes.Impl.HelloClientImpl"/>

</components>
aaa.dicon
<components>
    <component class="Seasar.Examples.Reference.Includes.Impl.HelloImpl">
        <property name="Message">"Hello Aaa!"</property>

    </component>

    <component name="aaa" class="Seasar.Examples.Reference.Includes.Impl.HelloClientImpl"/>
</components>
bbb.dicon
<components>
    <component class="Seasar.Examples.Reference.Includes.Impl.HelloImpl">
        <property name="Message">"Hello Bbb!"</property>
    </component>

    <component name="bbb" class="Seasar.Examples.Reference.Includes.HelloClientImpl"/>
</components>

各コンポーネントの内容は、次のようになります。


namespace Seasar.Examples.Reference.Includes
{
    public interface IHelloClient
    {
        void ShowMessage();
    }
}
namespace Seasar.Examples.Reference.Includes.Impl
{
    public class HelloClientImpl : IHelloClient
    {
        private IHello hello;

        public HelloClientImpl() {}
        
        public IHello Hello
        {
            get { return this.hello; }
            set { this.hello = value; }
        }

        public void ShowMessage()
        {
            Console.WriteLine(this.Hello.Message);
        }
    }
}
namespace Seasar.Examples.Reference.Includes
{
    public interface IHello
    {
        string Message
        {
            set;
            get;
        }
    }
}
namespace Seasar.Examples.Reference.Includes.Impl
{
    public class HelloImpl : IHello
    {
        private string helloMessage;
        
        public HelloImpl() {}

        public string Message
        {
            get { return this.helloMessage; }
            set { this.helloMessage = value; }
        }
    }
}

HelloImplはMessageプロパティを定義しているだけです。HelloClientのShowMessage()を呼び出した場合の実行結果は次のようになります。

rootの実行結果
Hello Aaa!

まず、S2Containerはroot.diconにHelloImplが登録されているかを検索します。root.diconにはないので、次にインクルード先のaaa.diconを検索します。 aaa.diconにはHelloImplが登録されているので、そのコンポーネントを使用します。

aaaの実行結果
Hello Aaa!

aaaは、aaa.diconに登録されているコンポーネントを使用します。自動でインジェクションを行う場合、 子供のS2Containerは親のS2Containerのコンポーネントを使用することはできません。 例えば、root.diconにHelloImplを登録していてもaaaには自動インジェクションされないということです。

bbbの実行結果
Hello Bbb!

aaaと同様にbbbもbbb.diconに登録されているコンポーネントを使用します。
このサンプルは、Seasar.ExamplesプロジェクトのS2/NET/Examples/Reference/Includes以下に用意されています。

名前空間

コンポーネントの定義を分割した場合に、複数のコンポーネント定義間で名前が衝突しないように、 componentsタグのnamespace属性で名前空間を指定することができます。

foo.dicon
<components namespace="Foo">
    <component name="aaa" .../>

    <component name="bbb" ...>
        <arg>aaa</arg>
    </component>
</components>
bar.dicon
<components namespace="Bar">
    <include path="foo.dicon"/>
    <component name="aaa" .../>

    <component name="bbb" ...>
        <arg>aaa</arg>
    </component>
    <component name="ccc" ...>

        <arg>foo.aaa</arg>
    </component>
</components>
app.dicon

<components>
    <include path="bar.dicon"/>
</components>

同一のコンポーネント定義内では、名前空間なしで参照できます。他のS2Container定義のコンポーネントを参照する場合は、名前空間.をコンポーネント名の頭につけます。foo.aaaとbar.aaaは同じ名前がついていますが、名前空間が異なっているので、違うコンポーネントとして認識されます。慣習として、定義ファイルの名前は、名前空間.diconにすることを推奨します。

インスタンス管理

S2Containerで、コンポーネントのインスタンスをどのように管理するのかを指定するのが、 componentタグのinstance属性です。デフォルトはsingletonで、 これは、IS2Container.GetComponent()によって返されるコンポーネントは常に同じだという意味です。 IS2Container.GetComponent()を呼び出すたびに、新たに作成されたコンポーネントを返して欲しい場合は、instance属性にprototypeを指定します。 リクエスト(System.Web.HttpRequest)ごとにコンポーネントを管理したい場合は、instance属性にrequestを指定します。 セッション(System.Web.SessionState.HttpSessionState)ごとにコンポーネントを管理したい場合は、instance属性にsessionを指定します。

プレゼンテーションのフレームワークと組み合わせるときに、プレゼンテーションフレームワークが作成したインスタンスに対して、 S2Containerで管理されているコンポーネントをセットしたい場合があります。 そのようなS2Container外のコンポーネントに対して Dependency Injectionしたいときには、次のメソッドを使用します。

- Seasar.Framework.Container.IS2Container#InjectDependency(Object outerComponent)
- Seasar.Framework.Container.IS2Container#InjectDependency(Object outerComponent, Type componentType)
- Seasar.Framework.Container.IS2Container#InjectDependency(Object outerComponent, string componentName)

第一引数には、外部のコンポーネントを指定します。第二引数には、外部コンポーネントのクラス、またはコンポーネント名を指定します。
そのとき、S2Container定義では、instance属性にouterを指定します。
instance属性 説明
singleton(default) IS2Container.GetComponent()を何度呼び出しても同じインスタンスが返されます。
prototype IS2Container.GetComponent()を呼び出すたびに新たなインスタンスが返されます。
request リクエスト毎に1つのインスタンスが作成されます。name属性に指定した名前で、コンポーネントがリクエストに格納されます。 requestを使う場合は、S2HttpModuleを設定する必要があります。
session セッション毎に1つのインスタンスが作成されます。name属性に指定した名前で、コンポーネントがセッションに格納されます。sessionを使う場合は、S2HttpModuleを設定する必要があります。
outer コンポーネントのインスタンスは、S2Container外で作成し、Dependency Injectionだけを行います。アスペクトコンストラクタ・インジェクションは適用できません。

ライフサイクル

initMethodやdestroyMethodでコンポーネントのライフサイクルもコンテナで管理することができます。 S2Containerの開始時(S2Container.Init())にinitMethodタグで指定したメソッドが呼び出され、 S2Containerの終了時(S2Container.Destroy())にdestroyMethodタグ で指定したメソッドが呼び出されるようになります。initMethodはコンポーネントがコンテナに登録した順番に実行され、 destroyMethodはその逆順に呼び出されることになります。instance属性がsingleton以外の場合、destroyMethodを指定しても無視されます。 System.Collections.Hashtable#Add()メソッドに初期化(aaaに111を設定)・終了処理(aaaにnullを設定)を設定する場合は、次のようになります。

<components namespace="bar">

    <component name="table" class="System.Collections.Hashtable">
        <initMethod name="Add">
            <arg>"aaa"</arg>
            <arg>111</arg>
        </initMethod>
        <destroyMethod name="Add">
            <arg>"aaa"</arg>
            <arg>null</arg>
        </destroyMethod>
    </component>
</components>

自動バインディング

コンポーネント間の依存関係は、型がインターフェースの場合、コンテナによって自動的に解決されます。これがS2Containerのデフォルトですが、componentタグのautoBinding属性を指定することで細かく制御することもできます。

autoBinding 説明
auto(default)

コンストラクタの引数が明示的に指定されている場合は、それに従います。
指定されていない場合、引数のないデフォルトコンストラクタが定義されている場合はそのコンストラクタを使います。
デフォルトのコンストラクタがない場合、コンストラクタの引数の数が1以上で、引数の型がすべてインターフェースのコンストラクタで最も引数の数が多いものを使います。
プロパティが明示的に指定されている場合はそれに従います。
明示的に指定されていないプロパティで、型がインターフェースの場合は自動的にバインドします。

constructor コンストラクタの引数が明示的に指定されている場合は、それに従います。
指定されていない場合、引数のないデフォルトコンストラクタが定義されている場合はそのコンストラクタを使います。
デフォルトのコンストラクタがない場合、コンストラクタの引数の数が1以上で、引数の型がすべてインターフェースのコンストラクタで最も引数の数が多いものを使います。
プロパティが明示的に指定されている場合は、それに従います。
property コンストラクタの引数が明示的に指定されている場合は、それに従います。
指定されていない場合は、デフォルトのコンストラクタを使います。
型がインターフェースのプロパティを自動的にバインドします。
none コンストラクタの引数が明示的に指定されている場合は、それに従います。
プロパティが明示的に指定されている場合はそれに従います。

詳しくは、自動バインディング(コンストラクタ・インジェクション)自動バインディング(プロパティ・インジェクション)を参照してください。

コンポーネントでS2Containerを利用する

コンポーネントはS2Containerに依存しないことが望ましいのですが、コンポーネントによっては、 S2Containerのメソッドを呼び出したい場合もあるでしょう。S2Container自身もcontainerという名前で、 登録されているので、arg,propertyタグのボディでcontainerを指定することで、コンテナのインスタンスを取得できます。 また、S2Container型のプロパティを定義しておいて自動バインディングで設定することもできます。 arg,propertyタグでcontainerを指定する場合は、次のようになります。

<components>
    <component class="Examples.Dicon.BarImpl">
        <arg>container</arg>
    </component>

    <component class="Examples.Dicon.FooImpl">
        <property name="Foo">container</property>
    </component>
</components>

app.diconの役割

すべてのS2Container定義のルートになる定義ファイルは、慣例でapp.diconという名前にします。app.diconにはコンポーネントの定義はしないようにしてください。 通常は名前空間の付かない場所に埋め込まれたリソースとして配置しておくと良いでしょう。

<components>

    <include path="Examples/foo.dicon"/>
    <include path="Examples/bar.dicon"/>
         <!-- 定義ファイルの数分記述します -->
</components>

AOPの適用

コンポーネントにAOPを適用することもできます。 ただし現在のS2Container.NETではAOPを適用するには、System.MarshalByRefObjectの派生クラスであるか、 インターフェース型でコンポーネントを受け取る必要があります。 例えば、ArrayListにTraceInterceptorを適用したい場合次のようにします。

<components>
    <component name="traceInterceptor"
               class="Seasar.Framework.Aop.Interceptors.TraceInterceptor"/>
               
    <component class="System.Collections.ArrayList">
        <aspect>traceInterceptor</aspect>
    </component>

    <component class="TestSeasar.Framework.Container.Factory.AspectTagHandlerTest+FooImpl">
        <aspect pointcut="Time, GetHashCode">traceInterceptor</aspect>
    </component>

</components>

aspectタグのボディでInterceptorの名前を指定します。 pointcut属性にカンマ区切りで対象となるメソッド名・プロパティ名を指定することができます。 pointcut属性を指定しない場合は、コンポーネントが実装しているインターフェースのすべてのメソッドが対象になります。 メソッド名には正規表現(System.Text.RegularExpressions.Regex)も使えます。この定義を使うサンプルは次のようになります。

private const string PATH = "Framework/Container/Factory/AspectTagHandlerTest.dicon";

[Test]
public void TestAspect()
{
    IS2Container container = S2ContainerFactory.Create(PATH);
			
    IList list = (IList) container.GetComponent(typeof(IList));
    int count = list.Count;

    IFoo foo = (IFoo) container.GetComponent(typeof(IFoo));
    int time = foo.Time;
    foo.ToString();
    int hashCode = foo.GetHashCode();
}

public interface IFoo
{
    int Time { get; }
    int GetHashCode();
    string ToString();
}

public class FooImpl : IFoo
{
    private int time_ = 3;

    public FooImpl()
    {
    }

    #region IFoo メンバ

    public int Time
        {
            get
            {
                return time_;
            }
        }

        public override int GetHashCode()
        {
            return base.GetHashCode();
        }

        public override string ToString()
        {
            return time_.ToString();
        }

        #endregion
    }

実行結果は次のようになります。

BEGIN System.Collections.ICollection#get_Count()
END System.Collections.ICollection#get_Count() : 0
BEGIN Seasar.Tests.Framework.Container.Factory.AspectTagHandlerTest+IFoo#get_Time()
END Seasar.Tests.Framework.Container.Factory.AspectTagHandlerTest+IFoo#get_Time() : 3
BEGIN Seasar.Tests.Framework.Container.Factory.AspectTagHandlerTest+IFoo#GetHashCode()
END Seasar.Tests.Framework.Container.Factory.AspectTagHandlerTest+IFoo#GetHashCode() : 1168

メタデータ

components、component、arg、propertyタグにメタデータを指定することもできます。 metaタグはメタデータを指定したいタグの子タグに指定します。例えば、componentsタグにメタデータを指定したい場合次のようにします。

<components>
    <meta name="aaa">111</meta>
</components>	

components、component、arg、propertyタグに指定したメタデータの情報は、IS2Container、IComponentDef、IArgDef、 IPropertyDefで定義されている次のメソッドで取得することが出来ます。

  • public int MetaDefSize
  • public IMetaDef GetMetaDef(int index)
  • public IMetaDef GetMetaDef(string name)
  • public IMetaDef[] GetMetaDefs(string name)

S2Container定義タグリファレンス

DOCTYPE

DOCTYPEは、XML宣言の次に指定します。下記のように指定してください。

<?xml version="1.0" encoding="utf-8"?>

<!DOCTYPE components PUBLIC "-//SEASAR2.1//DTD S2Container//EN"
"http://www.seasar.org/dtd/components21.dtd">
<components>
    <component name="hello"
            class="Seasar.Examples.Reference.Injection.HelloConstructorInjection">
        <arg>"Hello World!"</arg>
    </component>
    
    <component name="ConstructorInjection"
            class="Seasar.Examples.Reference.Injection.HelloConstructorInjectionClient" />
</components>

componentsタグ(必須)

ルートのタグになります。

namespace属性(任意)

名前空間を指定することができます。

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE components PUBLIC "-//SEASAR2.1//DTD S2Container//EN"
"http://www.seasar.org/dtd/components21.dtd">
<components namespace="hoge">

    ...
</components>

includeタグ(任意)

分割されたS2Containerの定義を取り込む場合に使います。

path属性(必須)

定義ファイルのパスを指定することができます。 定義ファイルのパスには、埋め込まれたリソースもしくはファイルシステムで指定することができます。 埋め込まれたリソースを使用する場合は、定義ファイルの名前空間を含む完全限定名です。 セパレータは、/です。 定義ファイルのビルドアクションプロパティは、埋め込まれたりソースに設定します。 C#プロジェクトの場合は、フォルダを作成すると名前空間が作成されます。 VB.NETプロジェクトの場合は、フォルダを作成しても名前空間は作成されません。 例えば、プロジェクトフォルダ/Sample/Logic/aaa.diconとすると、C#プロジェクトの場合は、 既定の名前空間/Sample/Logic/aaa.diconになります。 VB.NETの場合は、既定の名前空間/aaa.diconになります。 ファイルシステムを使用する場合は、一般的なファイルパスを指定します。 絶対パス、相対パスを指定できます。 埋め込まれたリソース、ファイルシステムの定義ファイルを混在させることもできます。 同じパスで埋め込まれたリソース、ファイルシステムの両方でヒットする場合は、 ファイルシステムの定義ファイルが優先されます。 componentタグの前に記述する必要があります。

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE components PUBLIC "-//SEASAR2.1//DTD S2Container//EN"
"http://www.seasar.org/dtd/components21.dtd">

<components>
    <include path="aaa/bbb/ccc.dicon" />
</components>

componentタグ(任意)

コンポーネントを定義します。

class属性(任意)

クラスの完全限定名を指定します。ボディで、JScript.NET式を使って コンポーネントを指定した場合は、class属性を省略することができます。 JScript.NET式を使った場合にclass属性を指定すると、型チェックを行います。

name属性(任意)

名前を指定することもできます。.NETの識別子として使えるものにします。詳しくは、 コンポーネントの取得を参照してください。

instance属性(任意)

S2Containerがどのようにコンポーネントのインスタンスを管理するのかを指定することができます。singleton(デフォルト)、prototype、outer、request、sessionを指定することができます。詳しくは、インスタンス管理を参照してください。

autoBinding属性(任意)

S2Containerがコンポーネントの依存関係をどのように解決するのかを指定できます。auto(デフォルト)、constructor、property、noneを指定することができます。詳しくは、自動バインディングを参照してください。

argタグ(任意)

componentタグの子タグとして使った場合は、コンストラクタの引数になります。 記述した順番でコンストラクタに渡されます。 initMethodタグdestroyMethodタグの子タグとして使った場合は、メソッドの引数になります。 記述した順番でメソッドに渡されます。 引数として渡される実際の値は、ボディで、JScript.NET式を使うか、子タグで、 componentタグを使います。

propertyタグ(任意)

componentタグの子タグとして使います。プロパティとして設定される実際の値は、 ボディで、JScript.NET式を使うか、子タグで、componentタグを使います。

name属性(必須)

プロパティ名を指定します。

metaタグ(任意)

componentsタグcomponentタグargタグpropertyタグの子タグとして使います。メタデータの値は、ボディで、JScript.NET式を使うか、子タグで、componentタグを使います。

name属性(任意)

メタ名を指定します。

initMethodタグ(任意)

componentタグの子タグとして使います。 引数は、子タグで、argタグを使います。name属性を書かずに、 JScript.NET式を使って、コンポーネントのメソッドを呼び出すこともできます。 initMethodタグが定義されているコンポーネント自身を表すself、Console.Outを表すout、 Console.Errorを表すerrがinitMethodタグ内だけで有効なオブジェクトとして使えます。

name属性(任意)

メソッド名を指定します。

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE components PUBLIC "-//SEASAR2.1//DTD S2Container//EN"

"http://www.seasar.org/dtd/components21.dtd">
<components>
    <component class="System.Collections.Hashtable">
        <initMethod name="Add">
            <arg>"aaa"</arg>
            <arg>111</arg>
        </initMethod>
        
        <initMethod>self.Add("aaa", 111)</initMethod>
        <initMethod>out.WriteLine("Hello")</initMethod>
    </component>
</components>

destroyMethodタグ(任意)

initMethodタグと同様です。

aspectタグ(任意)

アスペクトをコンポーネントに組み込みます。詳しくは、S2AOPのaspectタグの説明を参照してください。

descriptionタグ(任意)

componentsタグcomponentタグargタグpropertyタグの子タグとしてdescriptionタグを使うことができます。自由に説明を記述できます。

JScript.NET式

JScript.NETについては以下のドキュメントを参照して下さい。

S2Container.NET JScript.NET式

Example

以下のサンプルを実行する場合は、セットアップを行う必要があります。 Seasar.ExamplesプロジェクトはWindowsアプリケーションとして作成されています。 Seasar.Examplesプロジェクトをスタートアッププロジェクトに設定しF5キーを押して開始すると、 ExamplesExplorerが起動しExampleのソースコードと実行結果を確認することができます。

コンストラクタ・インジェクション

コンストラクタ・インジェクションを使ってメッセージを表示しましょう。作成するファイルは以下のとおりです。

  • インターフェース(IHello.cs)
  • 実装クラス(HelloConstructorInjection.cs)
  • diconファイル(HelloConstructorInjection.dicon)
  • 実行クラス(HelloConstructorInjection.cs中のHelloconstructorInjectionClientクラス)
インターフェースの作成
  • ShowMessage()を定義します。

先ず最初はインターフェースを考えます。インターフェースと実装を分離することで、 コンポーネントの利用者は、インターフェースを知っていれば実装のことは知らなくても済むようになります。 また、テストの時には実装をモックに置き換えることで簡単にテストできるようになります。

namespace Seasar.Examples.Reference.Injection
{
    public interface IHello
    {
        void ShowMessage();
    }
}
実装クラスの作成
  • 引数がstring型のコンストラクタを定義します。
  • ShowMessage()を実装します。

次はいよいよ実装です。コンストラクタでメッセージを受け取り、 ShowMessage()で受け取ったメッセージを出力します。

using System;
namespace Seasar.Examples.Reference.Injection
{
    public class HelloConstructorInjection : IHello
    {
        private string message;

        public HelloConstructorInjection(string message)
        {
            this.message = message;
        }

        public void ShowMessage()
        {
            Console.WriteLine(this.message);
        }
    }
}
diconファイルの作成
  • componentタグでコンポーネントを定義します。
  • componentタグの子タグのargタグでコンストラクタの引数値を定義します。

メッセージをコンポーネントに設定するのは、S2Containerの仕事です。 定義ファイルに基づいてコンポーネントを組み立てます。

Seasar.Examples/Reference/Injection/HelloConstructorInjection.dicon

<?xml version="1.0" encoding="utf-8" ?> 
<!DOCTYPE components PUBLIC "-//SEASAR2.1//DTD S2Container//EN"
"http://www.seasar.org/dtd/components21.dtd">
<components>
    <component name="hello"
            class="Seasar.Examples.Reference.Injection.HelloConstructorInjection">
        <arg>"Hello World!"</arg>
    </component>

    <component name="ConstructorInjection"
        class="Seasar.Examples.Reference.Injection.HelloConstructorInjectionClient" />
</components>
実行クラスの作成
using System;

using Seasar.Framework.Container;
using Seasar.Framework.Container.Factory;

namespace Seasar.Examples.Reference.Injection
{
    public class HelloConstructorInjectionClient
    {
        private static readonly String PATH = 
            "Seasar.Examples/Reference/Injection/HelloConstructorInjection.dicon";

        public void Main() 
        {
            // 型を指定してコンポーネントを取得する場合
            IS2Container container = S2ContainerFactory.Create(PATH);
            IHello hello = (IHello) container.GetComponent(typeof(IHello));
            hello.ShowMessage();

            // 名前を指定してコンポーネントを取得する場合
            IHello hello2 = (IHello) container.GetComponent("hello");
            hello2.ShowMessage();
        }
    }
}
実行結果

argタグで指定した文字列が正しく表示されていることが確認できます。

Hello World!
Hello World!

この演習は、Seasar.ExamplesプロジェクトのSeasar.Examples/Reference/Injection以下に用意されています。

プロパティ・インジェクション

プロパティ・インジェクションを使ってメッセージを表示しましょう。作成するファイルは以下のとおりです。

  • インターフェース(IHello.cs)(コンストラクタ・インジェクションと同じもの)
  • 実装クラス(HelloPropertyInjection.cs)
  • diconファイル(HelloPropertyInjection.dicon)
  • 実行クラス(HelloPropertyInjection.cs中のHelloPropertyInjectionClientクラス)
インターフェースの作成
  • ShowMessage()を定義します。

インターフェースはコンストラクタ・インジェクションの場合と同じです。 プロパティに対するgetアクセサ、setアクセサを定義する必要はありません。 なぜなら、Dependency Injectionするのにコンストラクタを使うのかsetアクセサを使うのかは実装の問題だからです。

namespace Seasar.Examples.Reference.Injection
{
    public interface IHello
    {
        void ShowMessage();
    }
}
実装クラスの作成
  • プロパティを定義します。
  • ShowMessage()を実装します。

次は実装です。プロパティ・メソッドでメッセージを受け取り、ShowMessage()で受け取ったメッセージを出力します。

using System;

namespace Seasar.Examples.Reference.Injection
{
    public class HelloPropertyInjection : IHello
    {
        private string message;

        public HelloPropertyInjection() {}
		
        public string Message
        {
            get { return this.message; }
            set { this.message = value; }
        }

        public void ShowMessage()
        {
            Console.WriteLine(this.message);
        }
    }
}
diconファイルの作成
  • componentタグでコンポーネントを定義します。
  • componentタグの子タグのpropertyタグでコンポーネントのプロパティ値を定義します。

Seasar.Examples/Reference/Injection/HelloPropertyInjection.dicon

<?xml version="1.0" encoding="utf-8"?>

<!DOCTYPE components PUBLIC "-//SEASAR2.1//DTD S2Container//EN"
"http://www.seasar.org/dtd/components21.dtd">
<components>
    <component class="Seasar.Examples.Reference.Injection.HelloPropertyInjection">
        <property name="Message">"Hello World!"</property>
    </component>
    
    <component name="PropertyInjection" 
        class="Seasar.Examples.Reference.Injection.HelloPropertyInjectionClient" />
</components>
実行クラスの作成
  • S2ContainerFactory.Create(string path)を呼び出してS2Containerを作成します。
  • GetComponent()を使用して、S2Containerからコンポーネントを取り出します。
  • 取得したコンポーネントのメソッドを呼び出します。
using System;

using Seasar.Framework.Container;
using Seasar.Framework.Container.Factory;

namespace Seasar.Examples.Reference.Injection
{
    public class HelloPropertyInjectionClient
    {
        private static readonly String PATH =
            "Seasar.Examples/Reference/Injection/HelloPropertyInjection.dicon";

        public void Main() 
        {
            IS2Container container = S2ContainerFactory.Create(PATH);
            IHello hello = (IHello) container.GetComponent(typeof(IHello));
            hello.ShowMessage();
        }
    }
}
実行結果

propertyタグで指定した文字列が正しく表示されていることが確認できます。

Hello World!

この演習は、Seasar.ExamplesプロジェクトのSeasar.Examples/Reference/Injection以下に用意されています。

メソッド・インジェクション

メソッド・インジェクションを使ってメッセージを表示しましょう。作成するファイルは以下のとおりです。

  • インターフェース(IHello.cs)
  • 実装クラス(HelloMethodInjection.cs)
  • diconファイル(HelloMethodInjection.dicon)
  • 実行クラス(HelloMethodInjection.cs中のHelloMethodInjectionClientクラス)
インターフェースの作成
  • ShowMessage()を定義します。

追加のメソッドを複数回呼び出すようなケースが代表的な使い方ですが、 今回の演習では、インターフェースはコンストラクタ・インジェクションの場合と同じにしました。

namespace Seasar.Examples.Reference.Injection
{
    public interface IHello
    {
        void ShowMessage();
    }
}
実装クラスの作成
  • AddMessage()を定義します。
  • ShowMessage()を実装します。

次は実装です。AddMessage(string message)でメッセージを複数回追加して、 ShowMessage()で受け取ったメッセージを出力します。

using System;
using System.Text;

namespace Seasar.Examples.Reference.Injection
{
    public class HelloMethodInjection : IHello
    {
        private StringBuilder builder = new StringBuilder();

        public HelloMethodInjection() {}
		
        public void AddMessage(string message)
        {
            this.builder.Append(message);
        }

        public void ShowMessage()
        {
            Console.WriteLine(this.builder.ToString());
        }
    }
}
diconファイルの作成
  • componentタグでコンポーネントを定義します。
  • componentタグの子タグのinitMethodタグでコンポーネントのメソッドの引数値を定義します。

先ずは、argタグを使ってAddMessage(string message)に"Hello "を指定します。
次にJScript.NET式を使ってAddMessage(string message)に"World!"を指定します。

Seasar.Examples/Reference/Injection/HelloMethodInjection.dicon

<?xml version="1.0" encoding="utf-8"?>

<!DOCTYPE components PUBLIC "-//SEASAR2.1//DTD S2Container//EN"
"http://www.seasar.org/dtd/components21.dtd">
<components>
    <component class="Seasar.Examples.Reference.Injection.HelloMethodInjection">
        <initMethod name="AddMessage">
            <arg>"Hello "</arg>
        </initMethod>
        <initMethod>self.AddMessage("World!")</initMethod>
    </component>
    
    <component name="MethodInjection" 
        class="Seasar.Examples.Reference.Injection.HelloMethodInjectionClient" />
</components>
実行クラスの作成
  • S2ContainerFactory.Create(string path)を呼び出してS2Containerを作成します。
  • GetComponent()を使用して、S2Containerからコンポーネントを取り出します。
  • 取得したコンポーネントのメソッドを呼び出します。
using System;

using Seasar.Framework.Container;
using Seasar.Framework.Container.Factory;

namespace Seasar.Examples.Reference.Injection
{
    public class HelloMethodInjectionClient
    {
        private static readonly String PATH = 
            "Seasar.Examples/Reference/Injection/HelloMethodInjection.dicon";

        public void Main() 
        {
            IS2Container container = S2ContainerFactory.Create(PATH);
            IHello hello = (IHello) container.GetComponent(typeof(IHello));
            hello.ShowMessage();
        }
    }
}
実行結果

initMethodタグで指定した文字列が正しく表示されていることが確認できます。

Hello World!

この演習は、Seasar.ExamplesプロジェクトのSeasar.Examples/Reference/Injection以下に用意されています。

自動バインディング(コンストラクタ・インジェクション)

自動バインディングでメッセージを表示してみましょう。作成するファイルは以下のとおりです。

  • インターフェース(IHello.cs)
  • インターフェースの実装クラス(AutoHelloConstructorInjection.cs)
  • diconファイル(AutoHelloConstructorInjection.dicon)
  • 実行クラス(AutoHelloConstructorInjection.cs中のAutoHelloConstructorInjectionClientクラス)
インターフェースの作成
  • ShowMessage()を定義します。
namespace Seasar.Examples.Reference.AutoBinding
{
    public interface IHello
    {
        void ShowMessage();
    }
}
実装クラスの作成
  • 引数がIDictionaryのコンストラクタを定義します。
  • ShowMessage()を実装します。

コンストラクタでIDictionaryを受け取り、 ShowMessage()でhelloをキーとしてIDictionaryから値を取得して出力します。

using System;
using System.Collections;

namespace Seasar.Examples.Reference.AutoBinding
{
    public class AutoHelloConstructorInjection : IHello
    {
        private IDictionary dictionary;

        public AutoHelloConstructorInjection(IDictionary dictionary)
        {
            this.dictionary = dictionary;
        }

        public void ShowMessage()
        {
            Console.WriteLine(dictionary["hello"]);
        }
    }
}
diconファイルの作成
  • componentタグでSystem.Collections.IDictionaryの実装クラスである System.Collections.Hashtableをコンポーネント定義します。
  • componentタグの子タグであるinitMethodタグで Hashtableにキーとして"hello"、値として"Hello World!"を定義します。
  • componentタグでAutoHelloConstructorInjectionをコンポーネント定義します。 autoBinding属性にautoを指定します。
    演習であるため auto を明示的に指定していますが、 autoBinding属性のデフォルト値であるため本来は省略します。

AutoHelloConstructorInjectionには、argタグが定義されていないことに注目してください。 コンストラクタ・インジェクションを行う場合、argタグを定義する必要がありますが、 S2Container内にIDictionaryの実装クラスが登録されていれば、 S2Containerがコンテナ内を検索して自動的に引数を設定します。 ただし、引数の型がインターフェースでない場合、自動バインディングはできません。

Seasar.Examples/Reference/AutoBinding/AutoHelloConstructorInjection.dicon

<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE components PUBLIC "-//SEASAR2.1//DTD S2Container//EN"
"http://www.seasar.org/dtd/components21.dtd">
<components>

    <component class="System.Collections.Hashtable">
        <initMethod name="Add">
            <arg>"hello"</arg>
            <arg>"Hello World!"</arg>
        </initMethod>
    </component>

    <component name="hello" autoBinding="auto"
      class="Seasar.Examples.Reference.AutoBinding.AutoHelloConstructorInjection" />
	
    <component name="AutoConstructorInjection" 
      class="Seasar.Examples.Reference.AutoBinding.AutoHelloConstructorInjectionClient" />

</components>
実行クラスの作成
using System;
using Seasar.Framework.Container;
using Seasar.Framework.Container.Factory;
namespace Seasar.Examples.Reference.AutoBinding
{
    public class AutoHelloConstructorInjectionClient
    {
        private static readonly String PATH =
            "Seasar.Examples/Reference/AutoBinding/AutoHelloConstructorInjection.dicon";

        public void Main() 
        {
            IS2Container container = S2ContainerFactory.Create(PATH);
            IHello hello = (IHello) container.GetComponent(typeof(IHello));
            hello.ShowMessage();
        }
    }
}
実行結果

Hashtableの値が表示されていることから、自動的にコンストラクタの引数を設定していることが確認できます。

Hello World!

この演習は、Seasar.ExamplesプロジェクトのSeasar.Examples/Reference/AutoBinding以下に用意されています。

自動バインディング(プロパティ・インジェクション)

自動バインディングでメッセージを表示してみましょう。作成するファイルは以下のとおりです。

  • インターフェース(IHello.cs)
  • インターフェースの実装クラス(AutoHelloPropertyInjection.cs)
  • diconファイル(AutoHelloPropertyInjection.dicon)
  • 実行クラス(AutoHelloPropertyInjection.cs中のAutoHelloPropertyInjectionClientクラス)
インターフェースの作成
  • ShowMessage()を定義します。
namespace Seasar.Examples.Reference.AutoBinding
{
    public interface IHello
    {
        void ShowMessage();
    }
}
実装クラスの作成
  • IDictionary型のプロパティを定義します。
  • ShowMessage()を実装します。

IDictionary MessageのsetアクセサでIDictionaryを受け取り、 ShowMessage()でhelloをキーとしてIDictionaryから値を取得して出力します。

using System;
using System.Collections;

namespace Seasar.Examples.Reference.AutoBinding
{
    public class AutoHelloPropertyInjection : IHello
    {
        private IDictionary dictionary;

        public AutoHelloPropertyInjection()
        {
        }
        
        public IDictionary Message
        {
            set { dictionary = value; }
        }

        public void ShowMessage()
        {
            Console.WriteLine(dictionary["hello"]);
        }
    }
}
diconファイルの作成
  • componentタグでSystem.Collections.IDictionaryの実装クラスであるSystem.Collections.Hashtableをコンポーネント定義します。
  • componentタグの子タグであるinitMethodタグでHashtableにキーとして"hello"、値として"Hello World!"を定義します。
  • componentタグでAutoHelloPropertyInjectionをコンポーネント定義します。 autoBinding属性にautoを指定します。
    演習であるため auto を明示的に指定していますが、 autoBinding属性のデフォルト値であるため本来は省略します。

AutoHelloPropertyInjectionには、propertyタグが定義されていないことに注目してください。 プロパティ・インジェクションを行う場合、propertyタグで任意のプロパティを定義する必要がありますが、 S2Container内にIDictionaryの実装クラスが登録されていれば、 S2Containerがコンテナ内を検索して自動的にプロパティを設定します。ただし、 プロパティの型がインターフェースでない場合、自動バインディングはできません。

Seasar.Examples/Reference/AutoBinding/AutoHelloPropertyInjection.dicon

<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE components PUBLIC "-//SEASAR2.1//DTD S2Container//EN"
"http://www.seasar.org/dtd/components21.dtd">
<components>

    <component class="System.Collections.Hashtable">
        <initMethod name="Add">
            <arg>"hello"</arg>
            <arg>"Hello World!"</arg>
        </initMethod>
    </component>

    <component name="hello" autoBinding="auto"
      class="Seasar.Examples.Reference.AutoBinding.AutoHelloPropertyInjection" />
	
    <component name="AutoPropertyInjection" 
      class="Seasar.Examples.Reference.AutoBinding.AutoHelloPropertyInjectionClient" />

</components>
実行クラスの作成
using System;
using Seasar.Framework.Container;
using Seasar.Framework.Container.Factory;
namespace Seasar.Examples.Reference.AutoBinding
{
    public class AutoHelloPropertyInjectionClient
    {
        private static readonly String PATH =
            "Seasar.Examples/Reference/AutoBinding/AutoHelloPropertyInjection.dicon";

        public void Main() 
        {
            IS2Container container = S2ContainerFactory.Create(PATH);
            IHello hello = (IHello) container.GetComponent(typeof(IHello));
            hello.ShowMessage();
        }
    }
}
実行結果

Hashtableの値が表示されていることから、自動的にプロパティを設定していることが確認できます。

Hello World!

この演習は、Seasar.ExamplesプロジェクトのSeasar.Examples/Reference/AutoBinding以下に用意されています。