第20章 Spring Framework 統合

Spring統合モジュールは、SpringベースのプロジェクトをSeamに容易なマイグレーションを可能にします。*** そして、Springアプリケーションに、 Seamの重要な機能、例えば、対話や洗練された永続コンテキスト管理を利用可能とします。

SeamのSpring対応は以下のような能力を提供します。

20.1. SeamコンポーネントをSpring beanにインジェクト

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にインジェクトされたならば、 そのシングルトンはその対話が終了した後も同じインスタンスの参照を持つでしょう。 この問題をスコープインピーダンスと呼びます。 Seamバイインジェクションは、 スコープインピーダンスがシステムを通じて呼び出す流れのように自然に維持することを保証しています。 Springでは、Seamコンポーネントのプロキシにインジェクトする必要があります。 そして、プロキシが呼ばれたときに参照は解決します。****

The <seam:instance/> tag lets us automatically proxy the Seam component.

<seam:instance id="seamManagedEM" name="someManagedEMComponent" proxy="true"/>
        
<bean id="someSpringBean" class="SomeSpringBeanClass">
    <property name="entityManager" ref="seamManagedEM">
</bean>

このサンプルは、Spring beanからSeam管理永続コンテキスト使い方の1つを示しています。 Spring OpenEntityManagerInViewフィルタとしてSeam管理永続コンテキストを利用するもっと堅牢な方法は、 将来のリリースで提供されるでしょう。

20.2. Spring beanをSeamコンポーネントにインジェクト****

Spring beanをSeamコンポーネントインスタンスにインジェクトするのはより簡単です。 実際、2つの可能なアプローチがあります。 approaches:

  • Spring beanをEL式を利用してインジェクト

  • Spring beanをSeamコンポーネントにする***

次の項で2番目のオプションを話題にします。 最も簡単なアプローチはEL式を通してSpring beanにアクセスすることです

Spring DelegatingVariableResolverは、 SpringとJSFを統合するためにSpringが提供するインテグレーションポイントです。 このVariableResolverは、のEL式中においてbean idによりすべてSpring beanを利用可能にしています。*** DelegatingVariableResolverfaces-config.xml:

に追加する必要があります。
<application>
    <variable-resolver>
        org.springframework.web.jsf.DelegatingVariableResolver
    </variable-resolver>
</application>

そして、@Inを使用してSpring beanをインジェクト可能です。

@In("#{bookingService}")
private BookingService bookingService;

EL式でのSpring beanの使用は制限されません。**** Spring beansはSeamでEL式が使用されるところでははどこでも使用が可能かもしれません。*** プロセスとページフロー定義、ワーキングメモリアサーションなど...

20.3. Spring beanをSeamコンポーネントにする

<seam:component/>名前空間ハンドラは、 どんなSpring beanもSeamコンポーネントにするために使用可能です。 Seamコンポーネントにしたいbeanの宣言の中に <seam:component/>タグを配置するだけです。

<bean id="someSpringBean" class="SomeSpringBeanClass" scope="prototype">
    <seam:component/>
</bean>

デフォルトでは、<seam:component/>は、 bean定義で与えたクラスと名前によってSTATELESSコンポーネントを生成するでしょう。 ときおり、FactoryBeanなどが使用されるとき、 Sprintのクラスはbean定義に現されているクラスではないかもしれません。 このような場合、classは指定されなければなりません。 名前の競合の可能性がある場合、 Seamコンポーネントは明示的に指定されるかもしれません。

Spring beanを特定のSeamスコープで管理したいならば、 <seam:component/>scope属性が使用されるかもしれません。 STATELESS以外の指定されたSeamスコープ Seamスコープがprototype以外に指定されれば、 Spring beanはprototypeスコープにされなければなりません。 既にあるSpring beanは通常ステートレスな特徴を基本的に持っています。 したがって、この属性は通常不要です。

20.4. Seam-scoped Spring beans***

Seam統合パッケージは、 Spring 2.0スタイルのカスタムスコープとしてSeamコンテキストの利用も可能にします。 これは、どのようなSeamコンテキスト中でもSpring beanの宣言を可能にします。 しかし、Springコンポーネントモデルはステートフル対応のために構築されていないことを再び留意し、 この機能は慎重をにご利用ください。 特に、セッションあるいは対話スコープのSpring beanのクラスタリングは根深い問題をはらんでおり、 広い範囲のスコープから狭い範囲のスコープのbean中にbeanまたはコンポーネントをインジェクトする場合には、 注意を払わねばなりません。

Spring bean factory設定で一度指定することで、 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/> と互換ではありません。 したがって、シングルトンにSeamスコープ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>

20.5. Spring Application Context as a Seam Component***

アプリケーションの持つSpringのApplicationContextを起動するために、 SpringのContextLoaderListenerは利用可能ですが、 いくつかの制約があります。

  • SeamListener後に、 Spring ApplicationContext は起動されなければなりません。

  • Seamのユニットテストや統合テストで使用するために、 Spring ApplicationContextを起動することは手が込んでいるかもしれません。

これら2つの制約を克服するために、 Spring統合はSpring ApplicationContextを起動するSeamコンポーネントを含みます。 このSeamコンポーネントをcomponents.xml中に、 <spring:context-loader/>定義を置いてください。 config-locations属性でSpring contextファイルの場所を指定してください。 2つ以上の設定ファイルが必要であれば、 標準のcomponents.xmlの複数値の慣例にしたがってネストして <spring:config-locations/>要素の中にそれらを置くことが可能です。

<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>