第3章 S2Container.Ruby リファレンス

目次

3.1. S2Container リファレンス
3.1.1. S2Containerの生成
3.1.2. コンポーネントの取得
3.1.3. Dependency Injection
3.1.4. コンストラクタ ブロック
3.1.5. デストラクタ ブロック
3.1.6. バインディングタイプの設定
3.1.7. インスタンスタイプの設定
3.2. S2ApplicationContext リファレンス
3.2.1. S2ApplicationContextの生成
3.2.2. コンポーネントの登録
3.2.3. S2Containerの生成
3.2.4. コンポーネントの選択
3.2.5. 自動アスペクト
3.2.6. Singleton S2Container インスタンスの管理

3.1. S2Container リファレンス

3.1.1. S2Containerの生成

S2Containerの生成はS2ApplicationContextクラスのcreateメソッドで行います。

require 's2container'
container = Seasar::Container::S2ApplicationContext.instance.create

S2ApplicationContext instanceを返すs2appメソッドを使用して、次のようにS2Containerを生成できます。

require 's2container'
container = s2app.create

3.1.2. コンポーネントの取得

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

S2Container#get_component(component_key)

引数にはコンポーネントのクラス、または文字列及びSymbolでコンポーネント名を指定します。 S2Containerに登録されているコンポーネント中に、指定したクラスを実装しているコンポーネントが複数ある場合は、S2Containerはどの コンポーネントを返せばよいのか判断できないためTooManyRegistrationRuntimeExceptionをraiseします。 実装コンポーネントがユニークに決まるクラスを指定してください。
コンポーネント名で取得する場合も同様に、1つのS2Containerの中でユニークとなるコンポーネント名を指定します。 同じ名前をもつコンポーネントが複数登録されている場合は、TooManyRegistrationRuntimeExceptionが発生します。

例として次のようなクラスを定義します。 s2componentメソッドの引数でコンポーネント名を文字列及びSymbolで設定します。

module Example
  class IndexAction
    s2component :name => "index"
  end

  class TopAction
    s2component :name => :top
  end

  class ResultAction
    s2component
  end
end

コンポーネント名を文字列で指定してコンポーネントを取得する場合は次のようになります。

require 's2container'
require 'example'
container = s2app.create
component = container.get_component("index")

クラスを指定してコンポーネントを取得する場合は次のようになります。componentメソッドはget_componenntメソッドのaliasです。

component = container.component(Example::IndexAction)

コンポーネント名をSymbolで指定してコンポーネントを取得する場合は次のようになります。getメソッドはget_componentメソッドのaliasです。

component = container.get(:top)

S2Contaienrからコンポーネントを取得するメソッドとして[]も使用できます。

component = container[Example::ResultAction]
[注意]NOTE

この例は example/example01 にあります。


3.1.3. Dependency Injection

S2ContainerのDependency Injectionは、自動バインディングによるプロパティ・インジェクションです。 インスタンス変数とアクセッサメソッドがプロパティとして扱われます。 自動バインディングは、コンポーネント間の依存関係を、プロパティ名やデフォルト値で指定されるクラスやコンポーネント名で解決します。

次のようなクラスを定義します。Actionクラスのコンストラクタinitializeメソッドで、インスタンス変数を定義します。インスタンス変数の デフォルト値に、Actionコンポーネントが依存する各ServiceコンポーネントをDIするための情報を設定しています。 また、attr_accessorメソッドでプロパティ「d」を定義しているため、コンポーネント名が「d」のコンポーネントがDIされます。

module Example
  class Action
    s2comp
    def initialize
      @a = nil
      @b = :di, "x.y.z.service_b"
      @c = :di, ServiceC
      @x_ = nil
      @_x = nil
    end
    attr_reader :a, :b, :c
    attr_accessor :d
  end

  class ServiceA
    s2comp :name => :a
  end

  class ServiceB
    s2comp :name => "service_b", :namespace => "x.y.z"
  end

  class ServiceC
    s2comp
  end

  class ServiceD
    s2comp :name => :d
  end
end

次のような実行ファイルを作成します。S2ContainerからActionコンポーネントを取得すると、インスタンス変数aからfに 各ServiceインスタンスがDIされたActionコンポーネントのインスタンスが返されます。

require 's2container'
require 'example'

container = s2app.create
component = container[Example::Action]

インスタンス変数名の先頭・後方にアンダースコアが付いたインスタンス変数は、自動バインディングの対象外となります。 コンポーネント間の依存関係を、プロパティのデフォルト値で設定するフォーマット一覧を次に示します。

表3.1 プロパティ値とDI

プロパティ値説明
nil インスタンス変数名のSymbol値をコンポーネント名としてDIします。インスタンス変数名が「@a」の場合、コンポーネント名は「:a」となります。 @property = nil
Array Arrayの sizeが2で、一番目の値が文字列かSymbolで「di」の場合に、二番目の値をコンポーネント名としてDIします。 @property = :di, "service"

[注意]NOTE

この例は example/example02 にあります。


3.1.4. コンストラクタ ブロック

コンストラクタ ブロックとは、コンポーネントの生成処理を行うブロックです。コンストラクタ ブロックは、s2componentメソッドで クラスをコンポーネントととして登録する際に設定します。

次のようなクラスを定義します。

module Example
  class Action
    def initialize(val)
      @val = val
    end
    attr_accessof :val
  end
end

次のような実行ファイルを作成します。s2componentメソッドにコンストラクタ ブロックを渡します。 コンストラクタ ブロックの最後の評価結果は、コンポーネントクラスとis_a?関係でなければいけません。

require 's2container'
require 'example'

s2component(:class => Example::Action) {
  Example::Action.new("abc")
} 

container = s2app.create
component = container[Example::Action]
p component.val          # -> "abc" 
[注意]NOTE

この例は example/example03 にあります。


3.1.5. デストラクタ ブロック

デストラクタ ブロックとは、コンポーネントのDestroy処理を行うブロックです。コンポーネントのインスタンス設定がsingletonの場合にのみ実行されます。 デストラクタ ブロックは、s2containerのdestroyメソッド内で実行されます。

次のようなクラスを定義します。

module Example
  class Action
    def init
      s2logger.debug(self.class){"init method called as constructor."}
    end
    def quit
      s2logger.debug(self.class){"quit method called as destructor."}
    end
  end
end

次のような実行ファイルを作成します。s2componentメソッドでコンポーネントを登録します。戻り値のComponentInfoDefに デストラクタ ブロックを設定します。

require 's2container'
require 'example'

component_info = s2component(:class => Example::Action) {
  # constructor block
  action = Example::Action.new
  action.init
  next action
}

component_info.destructor {|component|
  # destructor block
  component.quit
}

container = s2app.create
container.init                     # call constructor block
container.destroy                  # call destructor block


3.1.6. バインディングタイプの設定

S2Containerでは、コンポーネント単位でバインディングタイプを指定できます。バインディングタイプは次の2つがあります。

表3.2 バインディングタイプ

autoBinding説明
:auto (default) プロパティのデフォルト値により自動的にバインドします。
:none コンストラクタの引数が明示的に指定されている場合は、それに従います。
プロパティが明示的に指定されている場合は、それに従います。

s2componentメソッドでバインディングタイプを指定する場合は次のようになります。

class Service
  s2component :autobinding => :auto
end

3.1.7. インスタンスタイプの設定

S2Containerでは、コンポーネント単位でインスタンスの管理方法を指定できます。インスタンスタイプは次の2つがあります。

表3.3 インスタンスタイプ

instance説明
:singleton (default) S2Container.get_componentでコンポーネントを取得すると、常に同じインスタンスが返されます。
:prototype S2Container.get_componentでコンポーネントを取得すると、常に新規インスタンスが返されます。

s2componentメソッドでインスタンスタイプを指定する場合は次のようになります。

class Service
  s2component :instance => :singleton
end


© Copyright The Seasar Foundation and the others 2008-2009, all rights reserved.