Spring 統合モジュールにより、 SpringベースのプロジェクトをSeamに容易に移行できるようになるため、 対話のみならず Seam の各種の高度な永続コンテキスト管理など Seam の主要な機能を Springアプリケーションが 利用できるようになります。
Spring に対する Seam のサポートにより次のようなことが可能になります。
Seam コンポーネントインスタンスを Spring bean にインジェクトする
Spring bean を Seam コンポーネントにインジェクトする
Spring bean を Seam コンポーネントに変換する
Spring bean を Seam コンテキストに配置できるようにする
Seam コンポーネント で Spring Web アプリケーションを起動する
Seam コンポーネントインスタンスの Spring bean へのインジェクションは、 <seam:instance/> 名前空間ハンドラを使用して行います。 Seam 名前空間ハンドラを有効にするには、 Seam 名前空間を Spring bean 定義ファイルに追加しなければなりません。
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:seam="http://jboss.com/products/seam/spring-seam" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd http://jboss.com/products/seam/spring-seam http://jboss.com/products/seam/spring-seam-1.2.xsd">
これで、 Seam コンポーネントはいれの Spring bean にもインジェクション可能となりました。
<bean id="someSpringBean" class="SomeSpringBeanClass" scope="prototype"> <property name="someProperty"> <seam:instance name="someComponent"/> </property> </bean>
コンポーネント名の代わりに EL 式が利用可能です。
<bean id="someSpringBean" class="SomeSpringBeanClass" scope="prototype"> <property name="someProperty"> <seam:instance name="#{someExpression}"/> </property> </bean>
Seam コンポーネントインスタンスは、 Spring bean id で Spring bean へのインジェクションができるようになります。
<seam:instance name="someComponent" id="someSeamComponentInstance"/> <bean id="someSpringBean" class="SomeSpringBeanClass" scope="prototype"> <property name="someProperty" ref="someSeamComponentInstance"> </bean>
警告!
Seamは複数のコンテキストを持つステートフルなコンポーネントモデルに対応することを基本に設計されました。 Spring はそうではありません。 Seam のバイジェクションと異なり、 Spring のインジェクションはメソッド呼び出し時に発生しません。 その代わり、 Spring bean がインスタンス化されるときだけ、 インジェクションは発生します。 従って、 bean がインスタンス化されるときに利用可能なインスタンスは、 beanのライフサイクル全期間で bean が使用するものと同じインスタンスです。 例えば、 Seam 対話 スコープコンポーネントのインスタンスが 直接、 単一の Spring bean にインジェクトされると、 その単一の Spring bean はその対話が終了した後もずっと同じインスタンスに対する参照を保持します。 この問題をスコープインピーダンスと呼んでいます。 システム全体に呼び出しが流れるように、 Seam バイインジェクションはスコープインピーダンスが自然に維持されるようにします。 Spring では、 Seam コンポーネントのプロキシをインジェクトすることでプロキシが呼ばれた場合に参照を解決する必要があります。
<seam:instance/> タグで自動的に Seam コンポーネントをプロキシできるようになります。
<seam:instance id="seamManagedEM" name="someManagedEMComponent" proxy="true"/> <bean id="someSpringBean" class="SomeSpringBeanClass"> <property name="entityManager" ref="seamManagedEM"> </bean>
このサンプルは、 Spring bean から の Seam 管理永続コンテキストの使い方の 1 つを示しています。 (Seam 管理永続コンテキストを Spring OpenEntityManagerInView フィルタの代替として利用する場合、 さらに堅牢となる使用方法は今後のリリースで提供します。)
Spring bean を Seam コンポーネントインスタンスにインジェクトするのはさらに簡単です。 実際、 可能な方法は 2 つあります。
EL 式を使用して Spring bean をインジェクトする
Spring bean を Seam コンポーネントにする
2 番目のオプションについては次のセクションで説明します。 最も簡単な方法は EL 式を使って Spring bean にアクセスする方法です。
Spring DelegatingVariableResolver は、 Spring と JSF を統合するために Spring により提供されるインテグレーションポイントです。 この VariableResolver を使用すると、 bean id ですべての Spring bean を EL 式 で使用できるようにします。 DelegatingVariableResolverを faces-config.xml に追加する必要があります。
<application> <variable-resolver> org.springframework.web.jsf.DelegatingVariableResolver </variable-resolver> </application>
これを行うと @In を使って Spring bean をインジェクトできるようになります。
@In("#{bookingService}") private BookingService bookingService;
EL 式でインジェクションを行うために Spring bean を使用することに制限はありません。 Seam で EL 式が使用されるところならどこでも Spring bean を使用することができます。 プロセスとページフロー定義、 ワーキングメモリアサーションなど。
<seam:component/> 名前空間ハンドラを使用すると、 どんな Spring bean でも Seam コンポーネントにすることができます。 Seam コンポーネントにしたい bean の宣言内に <seam:component/> タグを配置するだけです。
<bean id="someSpringBean" class="SomeSpringBeanClass" scope="prototype"> <seam:component/> </bean>
デフォルトでは、 <seam:component/>は bean 定義で与えられるクラスと名前を付けて STATELESSコンポーネントを生成します。 ときおり、FactoryBean が使用される場合など、 Spring bean のクラス が bean 定義に出てくるクラスではないことがあります。 このような場合、 class は明示的に指定されなければなりません。 名前付けに競合の可能性がある場合、 Seam コンポーネント名を明示的に指定しても構いません。
Spring bean を特定の Seam スコープで管理したい場合、 <seam:component/> の scope 属性を使用することができます。 指定される Seam スコープが STATELESS ではない場合、 Spring bean は prototype にスコープされなければなりません。 既にある Spring bean は通常ステートレスな特徴を基本的に持っていますので、 この属性は一般的には不要になります。
Seam統合パッケージは、 Spring 2.0 スタイルのカスタムスコープとして Seam コンテキストの利用も可能にします。 どのような Seam コンテキスト中でもすべての Spring bean を宣言することができます。 ただし、 Spring コンポーネントモデルはステートフルに対応するようには構築されていないことを再度思い出してください。このことから、本機能の使用は慎重に行ってください。 特に、 セッションあるいは対話スコープの Spring beanのクラスタリングは根深い問題をはらんでおり、 広い範囲のスコープから狭い範囲のスコープの bean に bean またはコンポーネントをインジェクトする場合は、 十分に注意を払ってください。
Spring bean factory 設定で<seam:configure-scopes/> を一度指定すると、 すべての Seam スコープがカスタムスコープとして Spring bean に利用可能になります。 Spring bean を特定の Seam スコープに関連付けるには、 bean 定義の scope 属性で Seam スコープを指定してください。
<!-- Only needs to be specified once per bean factory--> <seam:configure-scopes/> ... <bean id="someSpringBean" class="SomeSpringBeanClass" scope="seam.CONVERSATION"/>
configure-scopes 定義内の prefix 属性を指定することによって、 スコープ名のプレフィックスを変更することができます。 (デフォルトのプレフィックスは seam. です。)
この方法で定義された Seam スコープの Spring bean は、 <seam:instance/> を使用することなく他の Spring bean にインジェクト可能です。 ただし、 スコープインピーダンスが必ず維持されるよう十分に注意してください。 Spring で一般的に使用される方法は、 bean 定義内での <aop:scoped-proxy/> の指定です。 しかし、 Seamスコープの Spring bean は <aop:scoped-proxy/> との互換性がありません。 したがって、 単一の bean に Seam スコープ Spring beanをインジェクトする必要がある場合、 <seam:instance/>を使用しなければなりません。
<bean id="someSpringBean" class="SomeSpringBeanClass" scope="seam.CONVERSATION"/> ... <bean id="someSingleton"> <property name="someSeamScopedSpringBean"> <seam:instance name="someSpringBean" proxy="true"/> </property> </bean>
アプリケーションの持つ Spring の ApplicationContext を起動するために Spring の ContextLoaderListener を使用することはできますが、 制約がいくつかあります。
Spring ApplicationContext は、 SeamListenerの後に起動されなければなりません。
Seam ユニット及び統合テストでの使用を目的とした Spring ApplicationContext の起動は厄介なことがあります。
これら 2 つの制約を克服するために Spring 統合には Spring ApplicationContext を起動する Seam コンポーネントが含まれています。 この Seam コンポーネントを使用するには、 <spring:context-loader/> の定義を components.xml に配置します。 config-locations 属性で使用する Spring コンテキストファイルの場所を指定します。 複数の設定ファイルが必要な場合は、 ネストされる <spring:config-locations/> エレメントに配置することができます。 これを行うには、 components.xml ファイルに複数の値エレメントを追加する基準に従ってください。
<components xmlns="http://jboss.com/products/seam/components" xmlns:spring="http://jboss.com/products/seam/spring" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://jboss.com/products/seam/components http://jboss.com/products/seam/components-1.2.xsd http://jboss.com/products/seam/spring http://jboss.com/products/seam/spring-1.2.xsd"> <spring:context-loader context-locations="/WEB-INF/applicationContext.xml"/> </components>