S2Containerを使用するためには、定義ファイルを作成する必要があります。
定義ファイルは、コンポーネントを組み立てるための設計書のようなものです。
形式はXMLで、拡張子は、diconです。
S2Containerの定義は、次のようになります。
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE components PUBLIC "-//SEASAR//DTD S2Container 2.4//EN"
"http://www.seasar.org/dtd/components24.dtd">
<components>
<component name="..." class="...">
...
</component>
<component name="..." class="...">
...
</component>
</components>
DOCTYPEは省略できません。diconファイルを作成する場合は、上記のサンプルをコピー&ペーストしてください。
ルートはcomponentsタグです。
コンポーネントごとに、componentタグを定義していきます。
componentタグのclass属性でコンポーネントのクラスの完全限定名を指定します。
name属性には、コンポーネント名を指定します。
詳細は、S2Container定義タグリファレンスを参照してください。
S2Containerを生成する方法は3通りあります。
SingletonS2ContainerFactoryを使用するサンプルは次のようになります。
SingletonS2ContainerFactory.init();
S2Container container = SingletonS2ContainerFactory.getContainer();
何も指定しない場合、デフォルトの定義ファイルはCLASSPATHで指定されているディレクトリにあるapp.diconになります。
通常のWebアプリケーションの場合、WEB-INF/classes/app.diconです。
定義ファイルのパスを指定する場合はinit()を呼び出す前にsetConfigPath(String Path)を使用します。
引数pathはCLASSPATHで指定されているディレクトリをルートとする定義ファイルの絶対パスです。
例えば、WEB-INF/classes/aaa.dicon の場合は aaa.dicon に、
WEB-INF/classes/aaa/bbb/ccc.dicon の場合は aaa/bbb/ccc.dicon になります。セパレータは、WindowsでもUnixでも/です。
private static final String PATH = "aaa/bbb/ccc.dicon";
...
SingletonS2ContainerFactory.setConfigPath(PATH);
SingletonS2ContainerFactory.init();
S2Container container = SingletonS2ContainerFactory.getContainer();
Webアプリケーションの場合、SingletonS2ContainerFactory.init()は、
S2ContainerServletが自動的に呼び出すので、
明示的に呼び出す必要はありません。
S2ContainerFactoryを使用するサンプルは次のようになります。
private static final String PATH = "aaa/bbb/ccc.dicon";
...
S2Container container = S2ContainerFactory.create(PATH);
この方法で取得したコンテナのインスタンスは、アプリケーションで管理する必要があります。
S2ContainerFactoryはSingletonS2ContainerFactoryが内部的に呼び出すクラスで、
通常は意識する必要はありません。
Webアプリケーションの場合、S2ContainerServletがSingletonS2ContainerFactory.init()を自動的に呼び出します。
S2ContainerServletを使うためには、web.xmlに次の項目を記述します。
<servlet>
<servlet-name>s2servlet</servlet-name>
<servlet-class>org.seasar.framework.container.servlet.S2ContainerServlet</servlet-class>
<init-param>
<param-name>configPath</param-name>
<param-value>app.dicon</param-value>
</init-param>
<init-param>
<param-name>debug</param-name>
<param-value>false</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>s2servlet</servlet-name>
<url-pattern>/s2servlet</url-pattern>
</servlet-mapping>
configPathで定義ファイルのパスを指定します。
debugパラメータをtrueにすると、次のようにして稼動中にS2Containerを再起動できます。
xxxはWebアプリケーションのコンテキスト名です。
http://localhost:8080/xxx/s2servlet?command=restart
また、次のようにS2Containerにデプロイされているコンポーネントの定義を見ることもできます。
http://localhost:8080/xxx/s2servlet?command=list
S2ContainerServletは、他のサーブレットよりもはやく起動されるようにload-on-startupタグを調整してください。
S2Containerからコンポーネントを取り出すには、次のメソッドを使用します。
S2Container.getComponent(Object componentKey)
componentKeyには、コンポーネントのクラスもしくはコンポーネント名を指定できます。
コンポーネントのクラスを指定する場合、コンポーネント instanceof クラスがtrueを返すクラスを指定することができます。
S2Containerの中に指定したクラスを実装しているコンポーネントが複数ある場合、
S2Containerは、どのコンポーネントを返せばよいのか判断できないため、
TooManyRegistrationRuntimeExceptionが発生します。
実装コンポーネントがユニークに決まるクラスを指定してください。
コンポーネント名で取得することもできます。
その場合も、同一の名前をもつコンポーネントが複数登録されている場合、
TooManyRegistrationRuntimeExceptionが発生します。
コンポーネント名指定の場合、スペルミスをする可能性もあるので、
できるだけクラス指定のほうが良いでしょう。
Java5でS2Tigerを利用している場合、SingletonS2Containerを使うことでキャストを不要にできます。
SingletonS2Containerを使う場合、あらかじめSingletonS2ContainerFactoryで、
S2Containerを初期化しておく必要があります。
SingletonS2Containerを利用するにはSeasar2.4以上が必要です。
Hoge hoge = (Hoge) container.getComponent(Hoge.class);
Hoge hoge = SingletonS2Container.getComponent(Hoge.class);
Hoge hoge = (Hoge) container.getComponent("hoge");
Hoge hoge = SingletonS2Container.getComponent("hoge");
Dependency Injectionには次のようなタイプがあります。
コンストラクタ・インジェクション、セッター・インジェクション、メソッド・インジェクションは組み合わせて使うこともできます。
コンストラクタの引数にDIを行なうのがコンストラクタ・インジェクションです。
コンストラクタの引数には、componentタグの子タグであるargタグを使って指定します。
<components>
<component name="..." class="...">
<arg>...</arg>
</component>
</components>
セッターメソッドにDIを行なうのがセッター・インジェクションです。
コンポーネントのプロパティには、componentタグの子タグであるpropertyタグを使って指定します。
プロパティ名はname属性で指定します。
<components>
<component name="..." class="...">
<property name="...">...</property>
</component>
</components>
メソッドにDIを行なうのがメソッド・インジェクションです。
コンポーネントのメソッドには、componentタグの子タグであるinitMethodタグを使って指定します。
メソッド名はname属性で指定します。
initMethodタグの子タグであるargタグで引数を指定することや、name属性を省略してボディでOGNL式を使うこともできます。
<components>
<component name="..." class="...">
<initMethod name="...">
<arg>...</arg>
</initMethod>
</component>
</components>
フィールドにDIを行なうのがフィールド・インジェクションです。
フィールドには、Bindingアノテーションを使って指定します。この機能は、2.4から利用できます。
@Binding("foo")
private Foo foo;
バージョン2.4.17からは、publicなフィールドをプロパティとして認識するようになったので、
publicフィールドを定義しておけば自動バインディングが
適用されます。上記のfooプロパティの例は次のようになります。
publicフィールドにBindingアノテーションを指定することもできます。
public Foo foo;
componentタグのinstance属性で、
コンポーネントのインスタンスをどのように管理するのかを指定します。
instance属性 |
説明 |
singleton(default) |
S2Container.getComponent()を何度呼び出しても同じインスタンスが返されます。 |
prototype |
S2Container.getComponent()を呼び出すたびに新たなインスタンスが返されます。 |
request |
リクエスト毎に1つのインスタンスが作成されます。
name属性に指定した名前で、コンポーネントがリクエストに格納されます。
requestを利用するためにはS2ContainerFilterの設定が必要です。 |
session |
セッション毎に1つのインスタンスが作成されます。
name属性に指定した名前で、コンポーネントがセッションに格納されます。
sessionを利用するためにはS2ContainerFilterの設定が必要です。 |
application |
Servletを使う場合は、ServletContext毎に1つのインスタンスが作成されます。
name属性に指定した名前で、コンポーネントがServletContextに格納されます。
applicationを利用するためにはS2ContainerFilterの設定が必要です。 |
outer |
コンポーネントのインスタンスは、S2Container外で作成し、Dependency Injectionだけを行います。アスペクト、コンストラクタ・インジェクションは適用できません。 |
DIの指定を省略した場合、
コンポーネント間の依存関係は、型および名前によってS2Containerが自動的に解決します。
componentタグのautoBinding属性を指定することで細かく制御することもできます。
autoBinding |
説明 |
auto(default) |
コンストラクタとプロパティの自動バインディングが適用されます。 |
constructor |
コンストラクタの自動バインディングが適用されます。 |
property |
プロパティの自動バインディングが適用されます。 |
none |
自動バインディンは適用されません。 |
コンストラクタの自動バインディングのルールは次の順番で適用されます。
- コンストラクタ・インジェクションが明示的に指定されている場合、
自動バインディングは適用されません。
- 引数のないデフォルトコンストラクタが定義されている場合、
自動バインディングは適用されません。
- 引数の型がすべてインターフェースで最も引数の数の多いコンストラクタを選択され、
その引数の型のコンポーネントが設定されます。
プロパティの自動バインディングのルールは次の順番で適用されます。
- セッター・インジェクションが明示的に指定されている場合、
自動バインディングは適用されません。
- プロパティの型を実装したコンポーネントがコンテナに1つ登録されていて、
プロパティ名とコンポーネント名が一致する場合、
そのコンポーネントが設定されます。
ただい、コンポーネント名にaaa_のようにサブパッケージ名がプレフィックスでついている場合、
にサブパッケージ名のプレフィックスは除いて、プロパティ名と比較します。
コンポーネント名については、こちらを参照してください。
- プロパティ名と同一のコンポーネントがコンテナに登録されていて、
プロパティに代入可能なら、 そのコンポーネントが設定されます。
- プロパティの型がインターフェースの場合、
コンテナをその型で検索し、見つかったコンポーネントが設定されます。
ただし、複数のコンポーネントが見つかった場合には、TooManyRegistrationRuntimeExceptionがスローされます。
- プロパティの型がインターフェースの配列の場合、
コンテナをその型で検索し、見つかったコンポーネントの配列が設定されます。
propertyタグのbindingType属性で、プロパティごとに細かく制御することもできます。
bindingType |
説明 |
must |
自動バインディングが適用されない場合、例外が発生します。 |
should(default) |
自動バインディングが適用されない場合、警告を通知します。 |
may |
自動バインディングが適用されない場合、何もおきません。 |
none |
自動バインディングは適用されません。 |
Webアプリケーションの場合、S2ContainerServletの初期化時にS2Container.init()が呼び出され、
S2ContainerServletの終了時にS2Container.destroy()が呼び出されます。
S2Container.init()が呼び出されたときに、シングルトンのコンポーネントは初期化され、
S2Container.destroy()が呼び出されたときに、シングルトンのコンポーネントは破棄されることになります。
Webアプリケーション以外の場合、明示的にS2Container.init()、
S2Container.destroy()を呼び出す必要があります。
コンポーネントを初期化するメソッドをinitMethodタグで指定できます。
シングルトンのコンポーネントはS2Container.init()時に初期化されますが、
それ以外のコンポーネントは取得されるときに初期化が行なわれます。
コンポーネントを破棄するメソッドをdestroyMethodタグで指定できます。
シングルトンのコンポーネントはS2Container.destroy()時に破棄されます。
それ以外のコンポーネントはdestroyMethodを指定しても無視されます。
initMethodはコンポーネントがコンテナに登録した順番に実行され、
destroyMethodはその逆順に呼び出されることになります。
HashMapを使ったサンプルは、次のようになります。
<components>
<component class="java.util.HashMap">
<initMethod name="put">
<arg>"aaa"</arg>
<arg>111</arg>
</initMethod>
<destroyMethod name="remvoe">
<arg>"aaa"</arg>
</destroyMethod>
</component>
</components>
環境名とは実行環境を表現する名前で、env.txt というテキストファイルによって指定します。
このenv.txt ファイルはクラスパス上に配置します。
WebアプリケーションではWEB-INF/classes になります。
いくつかの機能で、環境名によって処理をカスタマイズすることができます。
この機能はSeasar2.4以上が必要です。
標準的な名称は次のようになります。
ut
単体テスト環境を表します。
ct
結合テスト環境を表します。
it
統合テスト環境を表します。
product
運用環境を表します。env.txt ファイルが存在しない場合のデフォルトです。
定義ファイルに別の定義ファイルをインクルードすることができます。
<components>
<include path="bar.dicon"/>
</components>
includeタグのpath属性で定義ファイルのパスを指定します。
コンポーネントを探す場合、最初に自分自身に登録されているコンポーネントを探し、
見つからない場合は、インクルードいる順に子供の定義ファイルを検索し、
最初に見つかったコンポーネントが対象になります。
インクルード元の定義ファイルを変更することなくインクルード先の定義ファイルを切り替えたい場合があります。
記述上はデフォルトの定義ファイルをインクルードしているが実際にはデフォルト以外の定義ファイルを利用したいという場合です。
このような場合に利用できるのが定義ファイルの差し替えです。
定義ファイルを差し替えるには、s2container.diconにSimplePathResolver のコンポーネントを定義し、差し替え対象の定義ファイルと実際に利用したい定義ファイルを対応付けます。
例えば、デフォルトのjta.diconをWAS6用のjta-was6.diconに差し替えたい場合は次のように記述します。
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE components PUBLIC "-//SEASAR//DTD S2Container 2.4//EN"
"http://www.seasar.org/dtd/components24.dtd">
<components>
<include condition="#ENV == 'ut'" path="hotdeploy.dicon"/>
<include condition="#ENV != 'ut'" path="cooldeploy.dicon"/>
<component class="org.seasar.framework.container.factory.SimplePathResolver">
<initMethod name="addRealPath">
<arg>"jta.dicon"</arg>
<arg>"jta-was6.dicon"</arg>
</initMethod>
</component>
</components>
この場合、インクルード元の定義ファイルが次のように記述されていれば実際にはjta.diconではなくjta-was6.diconがインクルードされます。
<components>
<include path="jta.dicon"/>
</components>
定義ファイルの差し替え機能は、インクルード元の定義ファイルがjarファイル内にあり直接変更できない場合や、インクルード元の定義ファイルが複数あり一括でインクルード先を切り替えたい場合に役立ちます。
一つのアプリケーションで利用されるdiconファイルであっても、
状況によって異なった設定が必要になることがあります。
RDBMSの接続情報などは、環境によって変える必要があることがほとんどです、
このような場合に、diconファイルの記述を変更することなく、
環境に応じた設定をするための機能が条件インクルードです。
条件インクルードでは、環境ごとに必要な設定を記述したdiconファイルをインクルードすることができます。
条件インクルードは環境別のdiconファイルをインクルードするために、2つの方法を提供します。
- 暗黙的な条件インクルード
include タグのpath 属性で指定されたdicon名に、
環境名(環境を表す名前)をサフィックスとして持つdiconがあればそれをインクルードする機能です。
- 明示的な条件インクルード
OGNL式によって指定した条件が真となる場合のみdiconをインクルードする機能です。
暗黙的な条件インクルードとは、include タグのpath 属性で指定されたdicon名に、
環境名をサフィックスとして持つdiconがあればそれをインクルードする機能です。
暗黙的な条件インクルードを使う場合,インクルードする側のdiconは通常通り記述します.
<?xml version="1.0" encoding="UTF-8"?<
<!DOCTYPE components PUBLIC "-//SEASAR//DTD S2Container 2.4//EN"
"http://www.seasar.org/dtd/components24.dtd">
<components>
<include path="foo.dicon"/>
</components>
インクルードされる側のdiconは、拡張子を除いたファイル名の最後にサフィックスを付加します。
サフィックスは,アンダースコアと環境名をつなげたものです。
foo_ut.dicon
環境名がut の場合にインクルードされます。
foo_ct.dicon
環境名がct の場合にインクルードされます。
foo.dicon
環境名がut でもct でもない場合にインクルードされます。
より複雑な状況でインクルードするdiconを切り替えたい場合には、
include タグのcondition 属性でインクルードする条件をOGNL式で明示的に指定することができます。
この場合には、指定された条件が満たされた場合のみ、指定されたdiconがインクルードされます。
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE components PUBLIC "-//SEASAR//DTD S2Container 2.4//EN"
"http://www.seasar.org/dtd/components24.dtd"
>
<components>
<include condition="#ENV == 'ct'" path="hotdeploy.dicon"/>
<include condition="#ENV != 'ct'" path="cooldeploy.dicon"/>
</components>
この例では、#ENV で参照することのできる環境名が'ct' であればhotdeploy.diconを、
それ以外であればcooldeploy.diconをインクルードします。
include タグのcondition 属性には、
static メソッドの呼び出しを含む任意のOGNL式を記述することができます。
OGNL式については「OGNLガイド」を参照してください。
条件インクルードはSeasar2.4以上が必要です。
XInclude (XML Inclusion) は、
複数の XML ドキュメントを一つの XML ドキュメントに統合するための仕様です。
Seasar2.4 で導入された XInclude のサポートにより、複数の dicon ファイルを一つの dicon ファイルのように扱うことが可能になります。
前提条件
XInclude を利用するには、Java5 以降でかつXInclude に対応した XML パーサが必要です。
Java5 にバンドルされているXML パーサは XInclude に対応しています。
Teeda、S2JSF、Mayaa 等にバンドルされている Xerces 2.6.2 は XInclude に対応していません。
Xerces 2.6.2 は Tomcat 5.0 でも利用されています。
これらの環境で XInclude を使用するには次の設定が必要です.
META-INF/services ディレクトリを作成し、
javax.xml.parsers.SAXParserFactory というファイルを作成し、
以下の内容を記述します (SunのJDK/JREの場合)。
com.sun.org.apache.xerces.internal.jaxp.SAXParserFactoryImpl
XInclude の使い方
XInclude を使って他の dicon ファイルを取り込むには、次のように記述します。
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE components PUBLIC "-//SEASAR//DTD S2Container 2.4//EN"
"http://www.seasar.org/dtd/components24.dtd"
>
<components
xmlns:xi="http://www.w3.org/2001/XInclude"
>
<xi:include href="/foo.dicon"/>
<xi:include href="/bar.dicon"/>
</components>
- 文書型宣言で Seasar2.4 の DTD を指定します。
components タグで XInclude の名前空間を宣言します。
components の子タグに xi:include タグを記述します。
href 属性で取り込む dicon ファイルのパスを指定します。
パスの先頭は必ずスラッシュ ('/') にしてください.
これにより、foo.dicon と bar.dicon の内容 (components 子タグ) が取り込まれます。
xi:include 要素は component タグと混在して記述することができます。
foo.dicon と bar.dicon が次の内容だった場合
foo.dicon
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE components PUBLIC "-//SEASAR//DTD S2Container 2.4//EN"
"http://www.seasar.org/dtd/components24.dtd">
<components>
<component name="foo1">"Foo1"</component>
<component name="foo2">"Foo2"</component>
</components>
bar.dicon
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE components PUBLIC "-//SEASAR//DTD S2Container 2.4//EN"
"http://www.seasar.org/dtd/components24.dtd">
<components>
<component name="bar1">"Bar1"</component>
<component name="bar2">"Bar2"</component>
</components>
最初に示したdicon は次のように記述した場合と同じになります。
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE components PUBLIC "-//SEASAR//DTD S2Container 2.4//EN"
"http://www.seasar.org/dtd/components24.dtd"
>
<components
xmlns:xi="http://www.w3.org/2001/XInclude"
>
<component name="foo1">"Foo1"</component>
<component name="foo2">"Foo2"</component>
<component name="bar1">"Bar1"</component>
<component name="bar2">"Bar2"</component>
</components>
include タグとの違い
<include>タグと XInclude (<xi:include>) は一見似ているようですが、実際には大きく異なります。
次のように <include> を利用すると、それぞれの dicon ファイルを読み込んだ S2Containerが合計 3 つインスタンス化されます。
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE components PUBLIC "-//SEASAR//DTD S2Container 2.4//EN"
"http://www.seasar.org/dtd/components24.dtd"
>
<components
xmlns:xi="http://www.w3.org/2001/XInclude"
>
<include path="foo.dicon"/>
<include path="bar.dicon"/>
</components>
親となる dicon に定義されたコンポーネントからは foo.dicon と bar.dicon に定義されたコンポーネントが見えます (DI の対象となる)が、
foo.dicon に定義されたコンポーネントからは 親の dicon に定義されたコンポーネントも bar.dicon に定義されたコンポーネントも見えません (DI の対象とならない)。
bar.dicon に定義されたコンポーネントも 親の dicon に定義されたコンポーネントや foo.dicon に定義されたコンポーネントが見えません (DI の対象とならない)。
一方,XInclude を利用した場合には,親のdiconも,foo.dicon および bar.dicon も一つの S2 コンテナに読み込まれるため、
どこの dicon に定義したコンポーネントからであっても他の dicon に定義されたコンポーネントが見えます (DI の対象となる)。
また、次のようにaaa.diconとbbb.diconから同じjdbc.diconをXIncludeしたとします。
aaa.dicon
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE components PUBLIC "-//SEASAR//DTD S2Container 2.4//EN"
"http://www.seasar.org/dtd/components24.dtd"
>
<components
xmlns:xi="http://www.w3.org/2001/XInclude"
>
<xi:include path="jdbc.dicon"/>
</components>
bbb.dicon
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE components PUBLIC "-//SEASAR//DTD S2Container 2.4//EN"
"http://www.seasar.org/dtd/components24.dtd"
>
<components
xmlns:xi="http://www.w3.org/2001/XInclude"
>
<xi:include path="jdbc.dicon"/>
</components>
この場合、jdbc.diconの中身は、aaa.diconとbbb.diconに物理的に別のものとしてコピーされます。
一方、includeタグを使った場合は、aaa.diconとbbb.diconに取り込まれたjdbc.diconは同じものをさしています。
XIncludeは1つのdiconファイルを物理的に分割する場合に使ってください。
定義ファイルを分割した場合に、複数の定義ファイルで名前が衝突しないように、
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>
同じ定義ファイルのコンポーネントは名前空間なしで参照できます。
他の定義ファイルのコンポーネントを参照する場合は、名前空間.をコンポーネント名の頭につけます。
foo.aaaとbar.aaaは同じ名前がついていますが、名前空間が異なっているので、違うコンポーネントになります。
request、session、applicationでインスタンス管理をしたい場合、
S2ContainerFilterをweb.xmlに登録します。
<web-app>
<filter>
<filter-name>s2filter</filter-name>
<filter-class>org.seasar.framework.container.filter.S2ContainerFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>s2filter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-app>
定義ファイルに記述しなくても暗黙的に使えるコンポーネントが存在します。
これらのコンポーネントは、次のようにプロパティを定義しておけば自動的にDIされます。
S2Container container;
HttpServletRequest request;
HttpServletResponse response;
ServletContext application;
//ServletContextの属性にMapインターフェースでアクセスできます。
Map applicationScope;
//ServletContextの初期化パラメータにMapインターフェースでアクセスできます。
Map initParam;
//HttpSessionの属性にMapインターフェースでアクセスできます。
Map sessionScope;
//HttpServletRequestの属性にMapインターフェースでアクセスできます。
Map requestScope;
//Cookieの属性にMapインターフェースでアクセスできます。
Map cookie;
//HttpServletRequestのheaderにMapインターフェースでアクセスできます。戻り値はStringです。
Map header;
//HttpServletRequestのheaderにMapインターフェースでアクセスできます。戻り値はStringの配列です。
Map headerValues;
//HttpServletRequestのパラメータにMapインターフェースでアクセスできます。戻り値はStringです。
Map param;
//HttpServletRequestのパラメータにMapインターフェースでアクセスできます。戻り値はStringの配列です。
Map paramValues;
containerはコンポーネント自身が登録されているS2Containerになります。
ルートのS2Containerはcontainer.getRoot()で取得します。
container以外のコンポーネントを使うにはS2ContainerFilterが必要です。
コンポーネントにアスペクトを適用することもできます。
詳しい説明は、S2AOPを参照してください。
components、component、arg、propertyタグにメタデータを指定することもできます。metaタグはメタデータを指定したいタグの子タグに指定します。例えば、componentsタグにメタデータを指定したい場合次のようにします。
<components>
<meta name="aaa">111</meta>
</components>
自動バインディングにより、DIの設定はほぼ自動化できます。
さらに、コンポーネントの登録も自動化してしまおうというのが、コンポーネントの自動登録機能です。
ファイルシステムからクラスを検索としてコンポーネントを自動登録するコンポーネントです。
プロパティ |
説明 |
instanceDef |
自動登録されるコンポーネントに適用するInstanceDefを指定します。XMLで指定する場合、
@org.seasar.framework.container.deployer.InstanceDefFactory@REQUEST
のように指定します。 |
autoBindingDef |
自動登録されるコンポーネントに適用するAutoBindingDefを指定します。XMLで指定する場合、
@org.seasar.framework.container.assembler.AutoBindingDefFactory@NONE
のように指定します。 |
autoNaming |
クラス名からコンポーネント名を自動的に決定するコンポーネント。org.seasar.framework.container.autoregister.AutoNamingインターフェースを実装している必要があります。デフォルトは、org.seasar.framework.container.autoregister.DefaultAutoNamingクラスのインスタンスになります。 |
メソッド |
説明 |
addClassPattern |
自動登録したいクラスパターンを登録します。最初の引数は、コンポーネントのパッケージ名です。子供のパッケージも再帰的に検索します。2番目の引数は、クラス名です。正規表現が使えます。「,」区切りで複数記述することもできます。 |
addIgnoreClassPattern |
自動登録したくないクラスパターンを登録します。最初の引数は、コンポーネントのパッケージ名です。子供のパッケージも再帰的に検索します。2番目の引数は、クラス名です。正規表現が使えます。「,」区切りで複数記述することもできます。 |
Jarファイルの中からクラスを検索としてコンポーネントを自動登録するコンポーネントです。
プロパティ |
説明 |
jarFileNames |
対象のjarファイル名を指定します。正規表現も使えます。ただし、拡張子は含まれません。複数指定する場合は、「,」で区切ります。例えば、myapp.*, yourapp.*のようになります。 |
referenceClass |
このプロパティで指定されたクラスが存在するjarファイルの親ディレクトリをベースのディレクトリ(例えば、WEB-INF/lib)とみなします。デフォルトは、org.aopalliance.intercept.MethodInterceptor.classになります。 |
instanceDef |
自動登録されるコンポーネントに適用するInstanceDefを指定します。XMLで指定する場合、
@org.seasar.framework.container.deployer.InstanceDefFactory@REQUEST
のように指定します。 |
autoBindingDef |
自動登録されるコンポーネントに適用するAutoBindingDefを指定します。XMLで指定する場合、
@org.seasar.framework.container.assembler.AutoBindingDefFactory@NONE
のように指定します。 |
autoNaming |
クラス名からコンポーネント名を自動的に決定するコンポーネント。org.seasar.framework.container.autoregister.AutoNamingインターフェースを実装している必要があります。デフォルトは、org.seasar.framework.container.autoregister.DefaultAutoNamingクラスのインスタンスになります。 |
メソッド |
説明 |
addClassPattern |
自動登録したいクラスパターンを登録します。最初の引数は、コンポーネントのパッケージ名です。子供のパッケージも再帰的に検索します。2番目の引数は、クラス名です。正規表現が使えます。「,」区切りで複数記述することもできます。 |
addIgnoreClassPattern |
自動登録したくないクラスパターンを登録します。最初の引数は、コンポーネントのパッケージ名です。子供のパッケージも再帰的に検索します。2番目の引数は、クラス名です。正規表現が使えます。「,」区切りで複数記述することもできます。 |
ファイルシステムまたはJarファイルからクラスを検索としてコンポーネントを自動登録するコンポーネントです。
プロパティ |
説明 |
instanceDef |
自動登録されるコンポーネントに適用するInstanceDefを指定します。XMLで指定する場合、@org.seasar.framework.container.deployer.InstanceDefFactory@REQUESTのように指定します。 |
autoBindingDef |
自動登録されるコンポーネントに適用するAutoBindingDefを指定します。XMLで指定する場合、
@org.seasar.framework.container.assembler.AutoBindingDefFactory@NONE
のように指定します。 |
autoNaming |
クラス名からコンポーネント名を自動的に決定するコンポーネント。org.seasar.framework.container.autoregister.AutoNamingインターフェースを実装している必要があります。デフォルトは、org.seasar.framework.container.autoregister.DefaultAutoNamingクラスのインスタンスになります。 |
メソッド |
説明 |
addReferenceClass |
このメソッドで指定されたクラスが存在するディレクトリまたはJarファイルを基点としてクラスを検索します。 |
addClassPattern |
自動登録したいクラスパターンを登録します。最初の引数は、コンポーネントのパッケージ名です。子供のパッケージも再帰的に検索します。2番目の引数は、クラス名です。正規表現が使えます。「,」区切りで複数記述することもできます。 |
addIgnoreClassPattern |
自動登録したくないクラスパターンを登録します。最初の引数は、コンポーネントのパッケージ名です。子供のパッケージも再帰的に検索します。2番目の引数は、クラス名です。正規表現が使えます。「,」区切りで複数記述することもできます。 |
AutoNaming
AutoNamingによってコンポーネントに自動的に名前をつけることができます。
クラスの完全修飾名からパッケージ部分を除き、最後がImplまたはBeanで終わっていたら削除し、 先頭を小文字にした名前をコンポーネントの名前に設定します。 例えば、aaa.HogeImplクラスの場合、コンポーネント名は、hogeになります。
プロパティ |
説明 |
decapitalize |
コンポーネント名の先頭を小文字にする場合はtrueを指定します。デフォルトはtrueです。 |
メソッド |
説明 |
setCustomizedName |
デフォルトのルールに従わないクラスを登録します。最初の引数は、クラスの完全修飾名です。 2番目の引数は、コンポーネント名です。 |
addIgnoreClassSuffix |
クラス名の末尾から削除する部分を指定します。デフォルトでImplおよびBeanが登録されています。 |
addReplaceRule |
正規表現による置換ルールを追加します。最初の引数は正規表現です。2番目の引数は置換文字列です。 |
clearReplaceRule |
setCustomizedName、addIgnoreClassSuffix、addReplaceRuleで登録した変換規則をクリアします。デフォルトで登録されているImplおよびBeanもクリアされます。 |
パッケージ名またはその一部で修飾されたクラス名をコンポーネントの名前に設定します。 クラスの完全修飾名から最後がImplまたはBeanで終わっていたら削除し、 先頭を小文字、ピリオドの直後を大文字にした名前をコンポーネントの名前に設定します。
パッケージの先頭部分から不要な部分を削除することができます。
例えば、aaa.bbb.ccc.ddd.HogeImplクラスの場合で、先頭のaaa.bbbを削除するように指定した場合のコンポーネント名は、cccDddHogeになります。
プロパティ |
説明 |
decapitalize |
コンポーネント名の先頭を小文字にする場合はtrueを指定します。デフォルトはtrueです。 |
メソッド |
説明 |
setCustomizedName |
デフォルトのルールに従わないクラスを登録します。最初の引数は、クラスの完全修飾名です。 2番目の引数は、コンポーネント名です。 |
addIgnorePackagePrefix |
パッケージ名の先頭から削除する部分を指定します。 |
addIgnoreClassSuffix |
クラス名の末尾から削除する部分を指定します。デフォルトでImplおよびBeanが登録されています。 |
addReplaceRule |
正規表現による置換ルールを追加します。最初の引数は正規表現です。2番目の引数は置換文字列です。 |
clearReplaceRule |
setCustomizedName、 addIgnorePackagePrefix、 addIgnoreClassSuffix、 addReplaceRuleで登録した変換規則をクリアします。デフォルトで登録されているImplおよびBeanもクリアされます。 |
例
<component
class="org.seasar.framework.container.autoregister.FileSystemComponentAutoRegister">
<property name="autoNaming">
<component class="org.seasar.framework.container.autoregister.DefaultAutoNaming">
<initMethod name="setCustomizedName">
<arg>"examples.di.impl.HogeImpl"</arg>
<arg>"hoge2"</arg>
</initMethod>
</component>
</property>
<initMethod name="addClassPattern">
<arg>"examples.di.impl"</arg>
<arg>".*Impl"</arg>
</initMethod>
</component>
<component class="org.seasar.framework.container.autoregister.JarComponentAutoRegister">
<property name="referenceClass">
@junit.framework.TestSuite@class
</property>
<property name="jarFileNames">"junit.*"</property>
<initMethod name="addClassPattern">
<arg>"junit.framework"</arg>
<arg>"TestSuite"</arg>
</initMethod>
</component>
<component class="org.seasar.framework.container.autoregister.ComponentAutoRegister">
<initMethod name="addReferenceClass">
<arg>@aaa.bbb.ccc.ddd.HogeImpl@class</arg>
</initMethod>
<initMethod name="addClassPattern">
<arg>"aaa.bbb"</arg>
<arg>".*Impl"</arg>
</initMethod>
</component>
コンポーネントの自動登録により、コンポーネントの登録は自動化できます。
さらに、アスペクトの登録も自動化してしまおうというのが、アスペクトの自動登録機能です。
アスペクトについては、aspectタグを参照してください。
コンポーネントの自動登録と組み合わせる場合は、コンポーネントの自動登録の設定よりも後に、アスペクトの自動登録の設定を記述する必要があります。 アスペクトを適用されるコンポーネントは、アスペクトの自動登録の設定よりも後に記述する必要があります。
<components>
<!-- 1.コンポーネントの自動登録 -->
<component class="org.seasar.framework.container.autoregister.ComponentAutoRegister">
...
</component>
<!-- 2.アスペクトの自動登録 -->
<component class="org.seasar.framework.container.autoregister.AspectAutoRegister">
...
</component>
<!-- 3.その他のコンポーネント -->
<component class="...">
...
</component>
...
<components>
org.seasar.framework.container.autoregister.AspectAutoRegister
クラス名のパターンを指定してアスペクトを自動登録するコンポーネントです。
プロパティ |
説明 |
interceptor |
インターセプタを指定します。複数のインターセプタを指定したい場合は、InterceptorChainを使ってください。 |
pointcut |
インターセプタを適用するメソッドをカンマ区切りで指定します。
pointcutを指定しない場合は、コンポーネントが実装しているインターフェースのすべてのメソッドが対象になります。
インターフェースを実装していない場合、Object.classに属していないpublicでfinalではないメソッドが対象になります。
メソッド名には正規表現(JDK1.4のregex)も使えます。 |
メソッド |
説明 |
addClassPattern |
自動登録したいクラスパターンを登録します。最初の引数は、コンポーネントのパッケージ名です。子供のパッケージも再帰的に検索します。2番目の引数は、クラス名です。正規表現が使えます。「,」区切りで複数記述することもできます。 |
addIgnoreClassPattern |
自動登録したくないクラスパターンを登録します。最初の引数は、コンポーネントのパッケージ名です。子供のパッケージも再帰的に検索します。2番目の引数は、クラス名です。正規表現が使えます。「,」区切りで複数記述することもできます。 |
例
<include path="aop.dicon"/>
...
<component class="org.seasar.framework.container.autoregister.AspectAutoRegister"> <property name="interceptor">aop.traceInterceptor</property> <initMethod name="addClassPattern"> <arg>"examples.di.impl"</arg> <arg>".*Impl"</arg> </initMethod> </component>
あるインタフェースを実装したクラスに対してアスペクトを自動登録するコンポーネントです。
プロパティ |
説明 |
interceptor |
インターセプタを指定します。複数のインターセプタを指定したい場合は、InterceptorChainを使ってください。 |
targetInterface |
指定したインターフェースを実装しているコンポーネントに対して、アスペクトを適用します。 |
例
<include path="aop.dicon"/>
...
<component class="org.seasar.framework.container.autoregister.InterfaceAspectAutoRegister"> <property name="interceptor">aop.traceInterceptor</property>
<property name="targetInterface">@examples.Greeing@class</property> </component>
メタデータも自動登録することができます。
コンポーネントの自動登録と組み合わせる場合は、コンポーネントの自動登録の設定よりも後に、メタデータの自動登録の設定を記述する必要があります。 メタデータを参照するコンポーネントは、メタデータの自動登録の設定よりも後に記述する必要があります。
<components>
<!-- 1.コンポーネントの自動登録 -->
<component class="org.seasar.framework.container.autoregister.ComponentAutoRegister">
...
</component>
<!-- 2.メタデータの自動登録 -->
<component class="org.seasar.framework.container.autoregister.MetaAutoRegister">
...
</component>
<!-- 3.その他のコンポーネント -->
<component class="...">
...
</component>
...
<components>
org.seasar.framework.container.autoregister.MetaAutoRegister
クラス名のパターンを指定してメタデータを自動登録するコンポーネントです。
自動登録されるメタデータは、このコンポーネント自身の定義にautoRegisterという名前を持つメタデータの子として記述します。
メソッド |
説明 |
addClassPattern |
自動登録したいクラスパターンを登録します。最初の引数は、コンポーネントのパッケージ名です。子供のパッケージも再帰的に検索します。2番目の引数は、クラス名です。正規表現が使えます。「,」区切りで複数記述することもできます。 |
addIgnoreClassPattern |
自動登録したくないクラスパターンを登録します。最初の引数は、コンポーネントのパッケージ名です。子供のパッケージも再帰的に検索します。2番目の引数は、クラス名です。正規表現が使えます。「,」区切りで複数記述することもできます。 |
例
<component
class="org.seasar.framework.container.autoregister.MetaAutoRegister">
<meta name="autoRegister">
<meta name="hoge"</meta>
</meta>
<initMethod name="addClassPattern">
<arg>"examples.di.impl"</arg>
<arg>".*Impl"</arg>
</initMethod>
</component>
この例では、hogeという名前のメタデータが他のコンポーネント定義に自動登録されます。
コンポーネントの自動登録、
アスペクトの自動登録によりほとんど定義ファイルを書く必要はなくなりました。
しかし、コンポーネントのソースコードを書き換えるたびにアプリケーションサーバを再起動しなければならないという問題は、
まだ解決されていません。
この問題を解決するために開発されたのが、Seasar2.4から登場したHOT deploy機能です。
HOT deployを使うと、アプリケーションサーバを起動したままで、
ソースコードの修正が即座に反映されるので、「さくさく感のある開発」が可能になります。
開発時には便利なHOT deployですが、若干のオーバーヘッドがあり、
運用時には有効な機能だとはいえません。
運用時には、パフォーマンスや安定性が求められるでしょう。
このために用意されているのが、COOL deployです。
COOL deployを使うと、アプリケーションの起動時にすべてのデプロイを行い、
クラスのタイムスタンプチェックなどは一切行なわないので、
オーバヘッドなしで本来のパフォーマンスを発揮できます。
HOT deployとCOOL deployの中間に位置するのがWARM deployです。
JUnitなどでテストをすることを思い浮かべてください。
テストを実行しているときに、ソースコードを修正することはないので、
HOT deployの機能は不要です。
しかし、COOL deployのようにすべてのデプロイが、テストメソッドごとに行なわれると、
テストの時間が無駄に長くなってしまいます。
必要なコンポーネントだけがデプロイされるのが望ましいでしょう。
このように必要なコンポーネントだけがデプロイされ、
修正を即座に認識しないのがWARM deployの機能です。
HOT deploy、COOL deploy、WARM deployをあわせてSMART deployと呼びます。
HOT deployは、各開発者が個人のPCでテストするときに使うことを想定しています。
そのため、リクエストを複数同時に処理することはできません。
複数の開発者で使うときは、HOT deployは使わないようにしてください。
SMART deployの切り替えは、環境名を変えるだけでOKです。
例えば、次のようにs2container.diconが設定されている場合、
utのときにはWARM deploy、ctのときはHOT deploy、それ以外はCOOL deployになります。
<components>
<include condition="#ENV == 'ut'" path="warmdeploy.dicon"/>
<include condition="#ENV == 'ct'" path="hotdeploy.dicon"/>
<include condition="#ENV != 'ut' and #ENV != 'ct'" path="cooldeploy.dicon"/>
</components>
s2container.diconはS2Containerをカスタマイズするための定義ファイルです。
クラスパスの通っているディレクトリにおいておくだけでS2Containerが自動認識します。
通常は、WEB-INF/classesに配置します。
SMART deployで推奨しているパッケージ構成は次のようになります。
- examples.aaa
- examples.aaa.web.xxx
- examples.aaa.web.yyy
- examples.aaa.entity
- examples.aaa.dao
- examples.aaa.dto
- examples.aaa.service
- examples.aaa.util
- examples.aaa.helper
- examples.aaa.interceptor
- examples.aaa.converter
- examples.aaa.validator
examples.aaaをルートパッケージと呼びます。
ルートパッケージの配下に役割に応じてパッケージを配置します。
ルートパッケージは、convention.diconで指定します。
<component class="org.seasar.framework.convention.impl.NamingConventionImpl">
<initMethod name="addRootPackageName">
<arg>"examples.aaa"</arg>
</initMethod>
</component>
addRootPackage() メソッドの第2引数にfalse を指定することで、
ルートパッケージはHOT deploy非対象になります。
この場合、SMART deployによるコンポーネントの自動登録は行われますが,
HOT deployモードでコンポーネントがクラスローダにロードされた後にクラスを変更しても反映されません。
<component class="org.seasar.framework.convention.impl.NamingConventionImpl">
<initMethod name="addRootPackageName">
<arg>"examples.aaa"</arg>
<arg>false</arg>
</initMethod>
</component>
examples.aaa.web.xxx、examples.aaa.web.yyyをサブアプリケーションパッケージと呼びます。
xxx、yyyがサブアプリケーション名になります。
サブアプリケーションはユースケースと置き換えても良いでしょう。
複数の関連のある画面を1つにまとめたものがサブアプリケーションです。
典型的なWebアプリケーションは、一覧画面、編集画面、確認画面でサブアプリケーションが構成されます。
サブアプリケーションパッケージに格納するのは、ユースケース固有のクラスです。
HTMLと一対一に結びつくPageクラスやPageクラスとDTOの変換を行なうDxoクラスが、
サブアプリケーションパッケージに格納する代表的なクラスです。
examples.aaa.entityをエンティティパッケージと呼びます。
このパッケージには、テーブルと一対一に対応するEntityクラスを格納します。
examples.aaa.daoをDaoパッケージを呼びます。
このパッケージには、Entityと一対一に対応するDaoクラスを格納します。
examples.aaa.dtoをDtoパッケージを呼びます。
このパッケージには、DTOクラスを格納します。
examples.aaa.serviceをサービスパッケージと呼びます。
このパッケージには、複数のサブアプリケーションから共通に使われるユースケースを実装するServiceクラスを格納します。
examples.aaa.utilをユーティリティパッケージと呼びます。
このパッケージには、static なメソッドで構成されるユーティリティクラスを格納します。
examples.aaa.helperをヘルパパッケージと呼びます。
このパッケージにも、ユーティリティクラスを格納します。
ユーティリティパッケージとの違いは、DIやパラメータが必要なクラスを格納することです。
examples.aaa.interceptorをインタセプタパッケージを呼びます。
このパッケージには、AOPのモジュールを格納します。
examples.aaa.converterをコンバータパッケージを呼びます。
このパッケージには、データ変換を行なうモジュールを格納します。
examples.aaa.validatorをバリデータパッケージを呼びます。
このパッケージには、値の検証用のモジュールを格納します。
entity、serviceなどのルートパッケージ直下のパッケージを共通パッケージと呼びます。
共通パッケージには、複数のサブアプリケーションから共通に使われるクラスを格納します。
DTOクラスなどで特定のサブアプリケーションでしか使わない場合は、
Dtoパッケージではなく、サブアプリケーションパッケージに格納してください。
クラス名の先頭を小文字にしたものが基本的なコンポーネント名になります。
ただし、XXaaaPageのように2つ以上大文字が続いている場合は、
大文字のままです。これはJavaBeansの仕様です。
サブアプリケーションパッケージに格納されるコンポーネントは、
"サブアプリケーション名_"がプレフィックスにつきます。
アンダースコア(_)をプレフィックスの区切りに使っているので、
サブアプリケーション名やコンポーネント名にアンダースコア(_)は使えません。
これは、Seasar2の制限です。
サブアプリケーションパッケージ、
共通パッケージは、
さらにサブパッケージで区切ることもできます。
サブパッケージを使った場合は、"サブパッケージ名_"をプレフィックスに追加します。
サブパッケージはいくらでもネストすることができます
例えば、examples.aaa.web.bbb.ccc.DddPage のコンポーネント名は、
bbb_ccc_dddPage になります。
examples.aaa.service.bbb.CccService のコンポーネント名は、
bbb_cccService になります。
クリエータとはSMART deployの命名規約に従いコンポーネント定義を作成するコンポーネントの総称です。
クリエータは規約に従いインスタンス属性やコンポーネント名などコンポーネントに必要な情報を決定しコンポーネント定義を作成します。
Seasar2にはあらかじめ以下に示すクリエータが用意されています。
これらのクリエータは、それぞれ規約に合致するクラスのコンポーネント定義を作成します。
クリエータはcreator.diconに定義する必要があります。
クリエータ一覧
クリエータのクラスの単純名 |
コンポーネント化対象とするクラスの名前のサフィックス |
作成するコンポーネントのインスタンス属性 |
ActionCreator | Action | request |
ConverterCreator | Converter | prototype |
DaoCreator | Dao | prototype |
DtoCreator | Dto | request |
DxoCreator | Dxo | singleton |
HelperCreator | Helper | prototype |
InterceptorCreator | Interceptor | prototype |
LogicCreator | Logic | prototype |
PageCreator | Page | request |
ServiceCreator | Service | prototype |
ValidatorCreator | Validator | prototype |
クリエータが作成するコンポーネント定義に設定されるインスタンス属性は、あらかじめクリエータごとにデフォルトの値が指定されています。
クリエータは、コンポーネント名から対象となるクラスを一定のルールにしたがって見つけます。
例えば、hogeDaoという名前のコンポーネントがある場合、
最初にコンポーネント名のサフィックスを求めます。
サフィックスとはコンポーネント名の後ろから最初に大文字の部分までをさします。
hogeDaoの場合、サフィックスはDaoになります。
次にサフィックスの先頭を小文字(dao)にして、
パッケージ名を組み立てます。
daoの場合は、ルートパッケージ.daoになります。
コンポーネント名の先頭を大文字にしてパッケージ名とつなぎ合わせてクラス名を求めます。
今回の場合は、ルートパッケージ.dao.HogeDaoになります。
カスタマイザとはコンポーネント定義をカスタマイズするコンポーネントの総称です。
クリエータに呼び出されたカスタマイザは自身に定義されたカスタマイズ処理をコンポーネント定義に対し実行します。
カスタマイザの機能の代表例はアスペクト定義(インターセプタ)の追加です。
例えば、サービスのカスタマイザにトレース出力のアスペクト定義を設定すると、サービスのクリエータによって作成されたすべてのコンポーネントにトレース出力のインターセプタが自動で適用されます。
S2Containerにはdefault-customizer.diconに定義されたデフォルトカスタマイザとstd-customizer.diconに定義された標準カスタマイザがあらかじめ用意されています。
アプリケーションで定義するカスタマイザはcustomizer.diconに記述してください。
デフォルトカスタマイザはクリエータに関連付けられるカスタマイザです。
クリエータがコンポーネント定義を作成したあとにこれらのカスタマイザが呼び出されます。
デフォルトカスタマイザには以下のコンポーネントがあります。
コンポーネント名 | 説明 |
actionCustomizer | Action用のカスタマイザ |
converterCustomizer | Converter用のカスタマイザ |
daoCustomizer | Dao用のカスタマイザ |
dtoCustomizer | Dto用のカスタマイザ |
dxoCustomizer | Dxoカスタマイザ |
helperCustomizer | Helper用のカスタマイザ |
logicCustomizer | Logic用のカスタマイザ |
interceptorCustomizer | Interceptor用のカスタマイザ |
pageCustomizer | Page用のカスタマイザ |
serviceCustomizer | Service用のカスタマイザ |
validatorCustomizer | Validator用のカスタマイザ |
これらのコンポーネントの実体はorg.seasar.framework.container.customizer.CustomizerChain です。
CustomizerChain には任意の数のカスタマイザを設定(チェイン)可能ですが、デフォルトカスタマイザのコンポーネントには何も設定されていません。
したがって、デフォルトカスタマイザはクリエータから呼び出されても何の処理も実行しません。
デフォルトカスタマイザがそのように定義されている理由は、カスタマイザをどのように設定するかはアプリケーション開発者に委ねられているからです。
カスタマイザの設定はデフォルトカスタマイザの設定を上書きする形でcustomizer.diconに記述します。
その設定は通常CustomizerChain に任意の標準カスタマイザを追加することで行います。
標準カスタマイザは標準的に利用されることを想定したコンポーネントです。
標準カスタマイザには以下のコンポーネントがあります。
コンポーネント名 | 関連付けられたインターセプト名 | 説明 |
traceCustomizer | aop.traceInterceptor | トレース出力のためのカスタマイザ |
simpleTraceCustomizer | aop.simpleTraceInterceptor | 引数や戻り値を出力しない単純なトレースのためのカスタマイザ |
classLoaderAwareTraceCustomizer | aop.classLoaderAwareTraceInterceptor | クラスローダーの情報を含めたトレース出力のためのカスタマイザ |
syncCustomizer | aop.syncInterceptor | 同期処理のためのカスタマイザ |
traceThrowsCustomizer | aop.traceThrowsInterceptor | 例外のトレース出力のためのカスタマイザ |
toStringCustomizer | aop.toStringInterceptor | オブジェクトのフィールドの値を文字列化するためのカスタマイザ |
removeSessionCustomizer | aop.removeSessionInterceptor | メソッドの実行後にHTTPセッションから属性を削除するためのカスタマイザ |
commandTraceCustomizer | aop.traceInterceptor | do.*, initialize, prerenderをポイントカットとしてトレース出力するカスタマイザ |
requiredTxCustomizer | j2ee.requiredTx | Requiredのトランザクション属性を有効にするためのカスタマイザ |
requiresNewTxCustomizer | j2ee.requiresNewTx | RequiresNewのトランザクション属性を有効にするためのカスタマイザ |
mandatoryTxCustomizer | j2ee.mandatoryTx | Mandatoryのトランザクション属性を有効にするためのカスタマイザ |
notSupportedTxCustomizer | j2ee.notSupportedTx | NotSupportedのトランザクション属性を有効にするためのカスタマイザ |
neverTxCustomizer | j2ee.neverTx | Neverのトランザクション属性を有効にするためのカスタマイザ |
txAttributeCustomizer | j2ee.requiredTx | EJB3の@TransactionAttribute アノテーションで指定されたトランザクション属性を有効にするためのカスタマイザ (S2-Tigerが必要です) |
j2ee.requiresNewTx |
j2ee.mandatoryTx |
j2ee.notSupportedTx |
j2ee.neverTx |
s2DxoCustomizer | dxo.interceptor | Dxoを利用するためのカスタマイザ |
s2DaoCustomizer | dao.interceptor | S2Daoを利用するためのカスタマイザ |
kuinaDaoCustomizer | kuinaDao.interceptor | Kuina-Daoを利用するためのカスタマイザ |
dependencyLookupCustomizer | aop.dependencyLookupInterceptor | @DependencyLookup アノテーションの指定されたgetterメソッドがS2コンテナからルックアップしたコンポーネントを返すようにするためのカスタマイザ |
txAttributeCustomizer とdependencyLookupCustomizer を除いて、これらのコンポーネントの実体はorg.seasar.framework.container.customizer.AspectCustomizer です。
AspectCustomizer はコンポーネント定義にアスペクト定義を登録するカスタマイザです。
標準カスタマイザはインターセプタと関連づけられています。
実行時、標準カスタマイザは関連付けられたインターセプタからアスペクト定義を作成しコンポーネント定義に登録します。
アプリケーションで使用するカスタマイザの設定はcustomizer.diconに定義します。
例えば、サービスのコンポーネントに標準のカスタマイザであるtraceCustomizer とtraceThrowsCustomizer を適用する場合、次のように記述します。
<components>
<include path="default-customizer.dicon"/>
...
<component name="serviceCustomizer"
class="org.seasar.framework.container.customizer.CustomizerChain">
<initMethod name="addCustomizer">
<arg>traceCustomizer</arg>
</initMethod>
<initMethod name="addCustomizer">
<arg>traceThrowsCustomizer</arg>
</initMethod>
</component>
...
</components>
定義するコンポーネントの名前はデフォルトカスタマイザ一覧に示したコンポーネント名と同じにしてください。
こうすることでcusomizer.diconの定義がdefault-customizar.diconの定義より優先されます。
カスタマイザの設定例を紹介します。
ここで紹介する設定はすべてcusomizer.diconに記述されることを想定しています。
特定のパターンに従ってカスタマイザを適用する
パターンに合致するコンポーネントにのみカスタマイザを適用する場合
例えば、サービスのコンポーネントのうち「Hoge」で始まるクラス名をもつコンポーネントにtraceCustomizerを適用する場合、
次のようにaddClassPattern メソッドを使用し条件を引数で渡します。
第1引数にはパッケージ名、第2引数にはクラス名の正規表現を指定します。
第1引数のパッケージ名は、前方一致条件として使用されます。
たとえば、「example.hoge」を指定した場合「example.hoge」も「example.hoge.foo」もパターンに合致するとみなされます。
<component name="serviceCustomizer"
class="org.seasar.framework.container.customizer.CustomizerChain">
<initMethod name="addClassPattern">
<arg>"example.service"</arg>
<arg>"Hoge.*"</arg>
</initMethod>
<initMethod name="addCustomizer">
<arg>traceCustomizer</arg>
</initMethod>
</component>
パターンに合致するコンポーネントにはカスタマイザを適用しない場合
逆に、サービスのコンポーネントのうち「Hoge」で始まるクラス名をもつコンポーネントにはtraceCustomizerを適用しない場合、
次のようにaddIgnoreClassPattern メソッドを使用し条件を引数で渡します。
第1引数にはパッケージ名、第2引数にはクラス名の正規表現を指定します。
第1引数のパッケージ名は、前方一致条件として使用されます。
<component name="serviceCustomizer"
class="org.seasar.framework.container.customizer.CustomizerChain">
<initMethod name="addIgnoreClassPattern">
<arg>"example.service"</arg>
<arg>"Hoge.*"</arg>
</initMethod>
<initMethod name="addCustomizer">
<arg>traceCustomizer</arg>
</initMethod>
</component>
サービスのコンポーネントに適用する場合
serviceCustomizer にトランザクション制御を有効にするためのカスタマイザを設定します。
ここではRequiredのトランザクション属性に対応するrequiredTxCustomizer を使用します。
<component name="serviceCustomizer"
class="org.seasar.framework.container.customizer.CustomizerChain">
<initMethod name="addCustomizer">
<arg>requiredTxCustomizer</arg>
</initMethod>
</component>
この設定ではサービスのコンポーネントが実装するインタフェースのすべてのメソッドがトランザクション制御の対象になります。
@TransactionAttribute アノテーションを使ったサービスのコンポーネントに適用する場合
EJB3の@TransactionAttribute アノテーションで指定されたトランザクション属性に対応するトランザクション制御を有効にするためのカスタマイザを設定します。
ここではtxAttributeCustomizer を使用します。
<component name="serviceCustomizer"
class="org.seasar.framework.container.customizer.CustomizerChain">
<initMethod name="addCustomizer">
<arg>txAttributeCustomizer</arg>
</initMethod>
</component>
この設定では、サービスのコンポーネントが持つすべてのpublic メソッドがトランザクション制御の対象になります。
ただし、Object クラスで定義されているメソッドは除きます。
EJB3と異なり、インタフェースに定義されたメソッドでなくてもトランザクション制御の対象となります
(インタフェースを実装している必要はありません)。
EJB3ではないので、@Stateless 等のアノテーションを指定する必要もありません。
メソッドに@TransactionAttribute アノテーションが指定されていれば、そのvalue 属性の値で指定されたトランザクション属性が適用されます。
メソッドに@TransactionAttribute アノテーションが指定されていなければ、クラスに指定された@TransactionAttribute アノテーションが使われます。
クラスにも@TransactionAttribute アノテーションが指定されていなければ、デフォルトとしてrequiredTxが使われます。
ページのコンポーネントに適用する場合
pageCustomizer にトランザクション制御を有効にするためのカスタマイザを設定します。
addAspectCustomizer() メソッドの第1引数にインターセプタのコンポーネント名、
第2引数にトランザクション制御の対象となる特定のメソッドをポイントカットとして指定します。
<component name="pageCustomizer"
class="org.seasar.framework.container.customizer.CustomizerChain">
<initMethod name="addAspectCustomizer">
<arg>"j2ee.requiredTx"</arg>
<arg>"do.*, initialize, prerender"</arg>
</initMethod>
</component>
EJB 3.0のステートレスセッションBeanを利用する場合
EJB 3.0のステートレスセッションBeanはデフォルトでトランザクション制御を行う機能が備わっているのでcusomizer.diconに対する設定は不要です。
S2ContainerのEJB 3.0サポートについてはEJB3.0 Simplified APIを参照してください。
インターセプタを適用するAspectCustomizer のuseLookupAdapter プロパティにtrue を設定をします。
<component name="pageCustomizer"
class="org.seasar.framework.container.customizer.CustomizerChain">
<initMethod name="addCustomizer">
<arg>
<component class="org.seasar.framework.container.customizer.AspectCustomizer">
<property name="useLookupAdapter">true</property>
<property name="interceptorName">"app_aop.authenticateInterceptor"</property>
<property name="pointcut">"do.*"</property>
</component>
</arg>
</initMethod>
</component>
※ この例で使用した「app_aop.authenticateInterceptor」という名前のインターセプタは標準で用意されているものではありません。
複数のデータソースを利用する
データソースごとにカスタマイザを作成し、それらのカスタマイザをdaoCustomizerに設定してください。
S2Daoを使用した例についてはSMART deployで複数データソースに対応するには?を参照してください。
DOCTYPEは、XML宣言の次に指定します。下記のように指定してください。
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE components PUBLIC "-//SEASAR//DTD S2Container 2.3//EN"
"http://www.seasar.org/dtd/components23.dtd">
<components>
<component name="hello" class="examples.dicon.HelloConstructorInjection">
<arg>"Hello World!"</arg>
</component>
</components>
ルートのタグになります。
名前空間を指定することができます。Javaの識別子として使えるものにします
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE components PUBLIC "-//SEASAR//DTD S2Container 2.3//EN"
"http://www.seasar.org/dtd/components23.dtd">
<components namespace="hoge">
...
</components>
分割されたS2Containerの定義を取り込む場合に使います。
定義ファイルのパスを指定することができます。CLASSPATHで指定されているディレクトリをルートとする定義ファイルの絶対パスです。例えば、WEB-INF/classes/aaa.dicon の場合は aaa.dicon に、WEB-INF/classes/aaa/bbb/ccc.dicon の場合は aaa/bbb/ccc.dicon になりますセパレータは、WindowsでもUnixでも/です。
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE components PUBLIC "-//SEASAR//DTD S2Container 2.3//EN"
"http://www.seasar.org/dtd/components23.dtd">
<components>
<include path="aaa/bbb/ccc.dicon" />
</components>
コンポーネントを定義します。
クラスの完全限定名を指定します。ボディで、OGNL式を使ってコンポーネントを指定した場合は、class属性を省略することができます。OGNL式を使った場合にclass属性を指定すると、型チェックを行います。
名前を指定することもできます。Javaの識別子として使えるものにします。詳しくは、コンポーネントの取得を参照してください。
S2Containerがどのようにコンポーネントのインスタンスを管理するのかを指定することができます。singleton(デフォルト)、prototype、outer、request、sessionを指定することができます。詳しくは、インスタンス管理を参照してください。
S2Containerがコンポーネントの依存関係をどのように解決するのかを指定できます。auto(デフォルト)、constructor、property、noneを指定することができます。詳しくは、自動バインディングを参照してください。
componentタグの子タグとして使った場合は、コンストラクタの引数になります。記述した順番でコンストラクタに渡されます。 initMethodタグ、destroyMethodタグの子タグとして使った場合は、メソッドの引数になります。記述した順番でメソッドに渡されます。 引数として渡される実際の値は、ボディで、OGNL式を使うか、子タグで、componentタグを使います。
componentタグの子タグとして使います。プロパティとして設定される実際の値は、ボディで、OGNL式を使うか、子タグで、componentタグを使います。
プロパティ名を指定します。
プロパティごとに自動バインディングを細かく制御できます。must、should(デフォルト)、may、noneを指定することができます。詳しくは、自動バインディングを参照してください。
componentsタグ、componentタグ、argタグ、propertyタグの子タグとして使います。メタデータの値は、ボディで、OGNL式を使うか、子タグで、componentタグを使います。
メタ名を指定します。
componentタグの子タグとして使います。引数は、子タグで、argタグを使います。name属性を書かずに、OGNL式を使って、コンポーネントのメソッドを呼び出すこともできます。initMethodタグが定義されているコンポーネント自身を表す#self、System.outを表す#out、System.errを表す#errがinitMethodタグ内だけで有効なオブジェクトとして使えます。
メソッド名を指定します。
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE components PUBLIC "-//SEASAR//DTD S2Container 2.3//EN"
"http://www.seasar.org/dtd/components23.dtd">
<components>
<component class="java.util.HashMap">
<initMethod name="put">
<arg>"aaa"</arg>
<arg>111</arg>
</initMethod>
<initMethod>#self.put("aaa", 111)</initMethod>
<initMethod>#out.println("Hello")</initMethod>
</component>
</components>
initMethodタグと同様です。
Advice(以下Interceptor)をコンポーネントに組み込みます。
Interceptorの指定は、ボディで他のコンポーネントを参照するか、子タグでcomponentタグを使います。
1つのコンポーネントに複数のアスペクトを組み込んだ場合はアスペクトの登録順に組み込まれ実行されます。
- finalなクラスにはアスペクトを適用できません。
- finalまたはstaticまたは非publicなメソッドにはアスペクトを適用できません。
- aspectタグで指定されたコンポーネントは、
コンテナの初期化時にコンテナから取得されます。
そのため、aspectタグで指定されたコンポーネントのinstance属性がprototypeだったとしても、
Interceptor のメソッドが呼び出される度に新しいインスタンスが作成されるわけではありません。
singleton以外のスコープにしたい場合は、
InterceptorLifecycleAdapterを使ってください。
カンマ区切りで対象となるメソッド名を指定することができます。
pointcutを指定しない場合は、コンポーネントが実装しているインターフェースのすべてのメソッドが対象になります。
インターフェースを実装していない場合、Object.classに属していないpublicでfinalではないメソッドが対象になります。
メソッド名には正規表現(JDK1.4のregex)も使えます。
設定例
pointcut属性を指定してjava.util.DateのgetTime()メソッドとhashCode()メソッドを対象とする場合以下のようになります。
<component class="java.util.Date">
<aspect pointcut="getTime,hashCode">
<component class="org.seasar.framework.aop.interceptors.TraceInterceptor"/>
</aspect>
</component>
pointcutの対象から外したいメソッドがある場合は以下のようにします。
以下は「do」で始まり,その後に「ABC」が続くメソッドをpointcutの対象から外す例です。
doABC()メソッド、doABCDEF()メソッドがpointcutの対象から外れます。
<component class="java.util.Date">
<aspect pointcut="do(?!ABC).*">
<component class="org.seasar.framework.aop.interceptors.TraceInterceptor"/>
</aspect>
</component>
また、以下のような設定も可能です。
「do」で始まり,その後に「ABC」または「BCD」が続くメソッドをpointcutの対象から外す例です。
<component class="java.util.Date">
<aspect pointcut="do(?!ABC|BCD).*">
<component class="org.seasar.framework.aop.interceptors.TraceInterceptor"/>
</aspect>
</component>
InterTypeをコンポーネントに組み込みます。InterTypeの指定は、
ボディで他のコンポーネントを参照するか、子タグでcomponentタグを使います。
1つのコンポーネントに複数のInterTypeを組み込んだ場合はInterTypeの登録順に組み込まれます。
設定例
<component class="java.util.Date">
<interType>
<component class="org.seasar.framework.aop.intertype.PropertyInterType"/>
</interType>
</component>
componentsタグ、componentタグ、argタグ、propertyタグの子タグとしてdescriptionタグを使うことができます。自由に説明を記述できます。
S2Containerでは、式言語としてOGNLを利用しています。XMLの中で、文字列で記述した内容(式)をJavaのオブジェクトに変換するためのものだと思って間違いないと思います。
- 文字列は、"hoge"のように"で囲みます。
- charは、'a'のように'で囲みます。
- 数値は、123のようにそのまま記述します。
- 論理値は、true,falseのようにそのまま記述します。
- new java.util.Date(0)のようにクラスの完全限定名でコンストラクタを呼び出すことができます。
- @java.lang.Math@max(1, 2)のようにstaticなメソッドを呼び出した結果を参照することができます。
- @java.lang.String@classのようにクラスを参照できます。
- hoge.toString()のようにコンポーネントのメソッドを呼び出した結果を参照することができます。この例は、どこかでhogeという名前のコンポーネントが定義されているという前提です。
詳しくは、OGNLガイドを参照してください。
S2Containerでは、アノテーションの実装方法として、 Tigerアノテーション、
定数アノテーションの2種類を用意しています。
一般的にアノテーションといえば、Java 5から導入された Tigerアノテーションですが、
JDK1.4のユーザでも利用できるように、public static finalな定数を利用する定数アノテーションも用意しています。
componentタグのかわりに使えるのが、Componentアノテーションです。
Tigerアノテーションは以下のようになります。
@Component(name="xxx", instance=InstanceType.PROTOTYPE,
autoBinding=AutoBindingType.PROPERTY)
public class Xxx {
...
}
定数アノテーションは以下のようになります。
public static final String COMPONENT =
"name = xxx, instance = prototype, autoBinding = property";
propertyタグのかわりに使えるのが、Bindingアノテーションです。
Tigerアノテーションは以下のようになります。
@Binding("aaa2")
public void setAaa(String aaa) {
...
}
@Binding(bindingType=BindingType.NONE)
public void setBbb(String bbb) {
...
}
@Binding
public void setCcc(String ccc) {
...
}
@Binding
private Foo foo;
定数アノテーションはプロパティ名_BINDINGで指定します。
public static final String aaa_BINDING = "aaa2";
public static final String bbb_BINDING = "bindingType=none";
public static final String ccc_BINDING = null;
public void setAaa(Aaa aaa) {
...
}
public void setBbb(Bbb bbb) {
...
}
public void setCcc(Ccc ccc) {
...
}
aspectタグのかわりに使えるのが、Aspectアノテーションです。
aspectタグと異なり、複数定義することはできないので、 複数のインターセプタを適用したい場合は、
InterceptorChainを使ってください。
ポイントカットを指定したいときは、pointcut属性を指定します。
クラスに対するアノテーションの場合、pointcutを指定しないときは、
そのクラスが実装しているすべてのインターフェースのメソッドが対象になります。
インターフェースを実装していない場合、Object.classに属していないpublicでfinalではないメソッドが対象になります。
Tigerアノテーションは以下のようになります。
@Aspect("aop.traceInterceptor")
public class Xxx {
...
}
public class Xxx {
...
@Aspect("aop.traceInterceptor")
public void hoge() {
...
}
}
定数アノテーションは以下のようになります。pointcutを複数指定したい場合は、pointcut= get.*\nexecute.*のように\nで区切ってください。 \n以外の区切り文字を使ってはいけません。
public static final String ASPECT =
"value=aop.traceInterceptor, pointcut=getAaa";
interTypeタグのかわりに使えるのが、InterTypeアノテーションです。
Tigerアノテーションは以下のようになります。
@InterType({"aop.propertyInterType", "aop.someInterType"})
public class Xxx {
...
}
定数アノテーションは以下のようになります。
public static final String INTER_TYPE =
"aop.propertyInterType, aop.someInterType";
initMethodタグのかわりに使えるのが、InitMethodアノテーションです。
initMethodタグと異なり、OGNLの式を書いたり、引数を設定することはできません。
Tigerアノテーションは以下のようになります。
public class Xxx {
...
@InitMethod
public void init() {
...
}
}
定数アノテーションは以下のようになります。初期化メソッドを複数指定したい場合は、カンマ(,)で区切ってください。
public static final String INIT_METHOD = "init";
destroyMethodタグのかわりに使えるのが、DestroyMethodアノテーションです。
destroyMethodタグと異なり、OGNLの式を書いたり、引数を設定することはできません。
Tigerアノテーションは以下のようになります。
public class Xxx {
...
@DestroyMethod
public void destroy() {
...
}
}
定数アノテーションは以下のようになります。destroyメソッドを複数指定したい場合は、カンマ(,)で区切ってください。
public static final String DESTROY_METHOD = "destroy";
|