SeamFramework.org Community Documentation

- 前のページ
- 次のページ

## 第27章 Spring Framework 統合

Spring 統合モジュール (Seam IoC モジュールの一部) により Seam への Spring ベースとするプロジェクトの移植が容易になり、 Spring アプリケーションは対話や Seam の高度な永続コンテキスト管理など Seam の主要な機能を利用することができるようになります。

注意! Spring 統合コードは jboss-seam-ioc ライブラリに含まれています。 この依存性は本章に記載されているすべての seam-spring 統合技術に必要となります。

Spring の Seam サポートは次のような機能を提供します。

- Seam コンポーネントインスタンスを Spring Bean にインジェクトする

- Spring Bean を Seam コンポーネントにインジェクトする

- Spring Bean を Seam コンポーネントに変換する

- Spring Bean を Seam コンテキストに配置できるようにする

- Seam コンポーネント で Spring Web アプリケーションを起動する

- Spring PlatformTransactionManagement のサポート

- Spring の `OpenEntityManagerInViewFilter` および `OpenSessionInViewFilter` の代替として Seam 管理を提供します。

- `@Asynchronous` コールに対応する Spring `TaskExecutors` のサポート

## 27.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-2.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 はその対話が終了した後もずっと同じインスタンスに対する参照を保持します。 この問題を スコープインピーダンス (scope impedance) と呼んでいます。 システム全体に呼び出しが流れるように、 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 管理の永続コンテキストを使用する方法のひとつを示しています。 (Spring `OpenEntityManagerInView` フィルタの代替として Seam 管理の永続コンテキストを使用するより堅牢な方法については、 Spring で Seam 管理の永続コンテキストを使用する のセクションを参照してください。)

## 27.2. Spring Bean を Seam コンポーネントにインジェクトする

Spring Bean を Seam コンポーネントインスタンスにインジェクトするのはさらに簡単です。 実際、 可能な方法は 2 つあります。

- EL 式を使用して Spring Bean をインジェクトする

- Spring Bean を Seam コンポーネントにする

次のセクションでは 2 番目の選択肢について説明します。 もっとも容易な方法は EL を使って Spring Bean にアクセスします。

Spring の `DelegatingVariableResolver` は Spring を JSF と統合する場合に Spring によって提供される統合ポイントになります。 この `VariableResolver` はその Bean ID によって EL ですべての Spring Bean を利用可能にさせることができます。 `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 を使用することができます。 プロセスとページフロー定義、 ワーキングメモリアサーションなど。

## 27.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` が使用される場合など、 Spring Bean のクラス が Bean 定義に出てくるクラスではないことがあります。 このような場合、 `class` は明示的に指定されなければなりません。 名前付けに競合の可能性がある場合、 Seam コンポーネント名を明示的に指定しても構いません。

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

## 27.4. Seam スコープの Spring Bean

Seam 統合パッケージにより Seam のコンテキストを Spring 2.0 スタイルのカスタムスコープとして使用することもできるようになります。 これによりいずれの 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.` です。)

デフォルトではこの方法で登録される Spring コンポーネントのインスタンスは `@In` を使って参照される場合に自動的には作成されません。 インスタンスを自動作成させるにはインジェクションポイントで `@In(create=true)` を指定して自動作成される特定 Bean を識別するか、 `configure-scopes` の `default-auto-create` 属性を使って Seam スコープを使用する Spring Bean はすべて自動作成されるようにします。

この方法で定義された 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

    >

## 27.5. Spring の PlatformTransactionManagement を使用する

Spring は拡張可能なトランザクション管理抽象を提供し、 多くのトランザクション API (JPA、 Hibernate、 JDO、 JTA など) に対応します。 また、 Spring は Websphere や Weblogic などの多くのアプリケーションサーバーの TransactionManagers との堅固な統合を実現します。 Spring トランザクション管理はネストされるトランザクションなど多くの高度な機能のサポートを提供し、 REQUIRES_NEW や NOT_SUPPORTED のような完全 Java EE トランザクション伝播のルールに対応します。 詳細については Spring のドキュメント ここ を参照してください。

Seam が Spring のトランザクションを使用するよう設定するには、 SpringTransaction コンポーネントを以下のように有効にします。

    <spring:spring-transaction platform-transaction-manager="#{transactionManager}"/>

`spring:spring-transaction` コンポーネントは同期のコールバックに Spring トランザクション同期の機能を利用します。

## 27.6. Spring で Seam 管理の永続コンテキストを使用する

Seam のパワフルな機能のひとつにその対話スコープと対話が生きている間 EntityManager をオープンにしておく機能があります。 これによりエンティティの分離や再併合に関連する多くの問題が解消され、 深刻な `LazyInitializationException` の発生を軽減することができます。 Spring は Web の一要求のスコープを越えて永続コンテキストを管理する方法は提供していません (`OpenEntityManagerInViewFilter`)。 このため、 Spring が JPA との統合に提供しているのとすべて同じツールを使った Seam 管理の永続コンテキストへのアクセスを Spring 開発者に持たせることができるとよいでしょう (`PersistenceAnnotationBeanPostProcessor`、 `JpaTemplate` など)。

Seam は提供される JPA ツールを使って Spring が Seam 管理永続コンテキストにアクセスする方法を提供します。 これにより Spring アプリケーションに対して対話スコープの永続コンテキスト機能を実現します。

この統合作業により次のような機能を実現します。

- Spring 提供ツールを使った Seam 管理永続コンテキストへの透過的なアクセス

- Web 要求以外での Seam 対話スコープ永続コンテキストへのアクセス (非同期の quartz ジョブなど)

- Seam 管理永続コンテキストと Spring 管理トランザクションとの併用が可能 (手作業による永続コンテキストのフラッシュが必要)

Spring の永続コンテキスト伝播モデルは EntityManagerFactory ごと一つの EntityManager しかオープンにしないため、 Seam 統合は EntityManagerFactory を Seam 管理永続コンテキストでラップすることで動作します。

    <bean id="seamEntityManagerFactory" class="org.jboss.seam.ioc.spring.SeamManagedEntityManagerFactoryBean">

               <property name="persistenceContextName" value="entityManager"/>

    </bean

    >

「persistenceContextName」は Seam 管理の永続コンテキストコンポーネントの名前になります。 デフォルトではこの EntityManagerFactory には Seam コンポーネント名と同等の unitName があり、 この場合は「entityManager」になります。 別の unitName を与えたい場合は次のようにして persistenceUnitName を与えることができます。

    <bean id="seamEntityManagerFactory" class="org.jboss.seam.ioc.spring.SeamManagedEntityManagerFactoryBean">

               <property name="persistenceContextName" value="entityManager"/>

            <property name="persistenceUnitName" value="bookingDatabase:extended"/>

    </bean

    >

これでこの EntityManagerFactory をいずれの Spring 提供のツールでも使用することができるようになります。 たとえば、 Spring の `PersistenceAnnotationBeanPostProcessor` を使用すると前とまったく同じになります。

    <bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor"/>

Spring では実際の EntityManagerFactory を定義するが Seam 管理の永続コンテキストを使用したい場合は `defaultPersistenceUnitName` プロパティを指定してデフォルトで使用したい persistenctUnitName を `PersistenceAnnotationBeanPostProcessor` に指示することができます。

`applicationContext.xml` は次に似たようなものになります。

    <bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalEntityManagerFactoryBean">

            <property name="persistenceUnitName" value="bookingDatabase"/>

    </bean>

    <bean id="seamEntityManagerFactory" class="org.jboss.seam.ioc.spring.SeamManagedEntityManagerFactoryBean">

               <property name="persistenceContextName" value="entityManager"/>

            <property name="persistenceUnitName" value="bookingDatabase:extended"/>

    </bean>

    <bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor">

            <property name="defaultPersistenceUnitName" value="bookingDatabase:extended"/>

    </bean

    >

`component.xml` は次に似たようなものになります。

    <persistence:managed-persistence-context name="entityManager"

            auto-create="true" entity-manager-factory="#{entityManagerFactory}"/>

`JpaTemplate` および `JpaDaoSupport` は Seam 管理永続コンテキスト用となるため、 Seam 管理永続コンテキストに対して同じ方法で設定します。

    <bean id="bookingService" class="org.jboss.seam.example.spring.BookingService">

            <property name="entityManagerFactory" ref="seamEntityManagerFactory"/>

    </bean

    >

## 27.7. Spring で Seam 管理の Hibernate セッションを使用する

Seam Spring 統合により Spring のツールを使った Seam 管理 Hibernate セッションへの完全アクセスに対応することもできます。 この統合は JPA 統合 に非常に似ています。

Spring の JPA 統合と同様に Spring の伝播モデルは一トランザクションの一EntityManagerFactory ごとに一つの EntityManager しか Spring ツールに対して利用できるようオープンにしません。 このため、 Seam Session 統合は proxy SessionFactory を Seam 管理の Hibernate セッションコンテキストでラップすることにより動作します。

    <bean id="seamSessionFactory" class="org.jboss.seam.ioc.spring.SeamManagedSessionFactoryBean">

            <property name="sessionName" value="hibernateSession"/>

    </bean

    >

「sessionName」は `persistence:managed-hibernate-session` コンポーネントの名前になります。 これでこの SessionFactory はいずれの Spring 提供ツールでも使用することができるようになります。 この統合は `SeamManagedSessionFactory` で getCurrentInstance() を呼び出している場合であれば `SessionFactory.getCurrentInstance()` に対する呼び出しにも対応します。

## 27.8. Seam コンポーネントとしての Spring Application Context

アプリケーションの持つ 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-2.2.xsd

                                    http://jboss.com/products/seam/spring

                                    http://jboss.com/products/seam/spring-2.2.xsd">

            <spring:context-loader config-locations="/WEB-INF/applicationContext.xml"/>

    </components

    >

## 27.9. @Asynchronous に Spring の TaskExecutor を使用する

Spring はコードを非同期に実行するために `TaskExecutor` と呼ばれる抽象を提供します。 Spring Seam 統合では `@Asynchronous` メソッドのコールを直ちに実行するために Spring の `TaskExecutor` を使用できます。 この機能を有効にするには `SpringTaskExecutorDispatchor` をインストールしてから次のように Spring Bean 定義の taskExecutor を与えます。

    <spring:task-executor-dispatcher task-executor="#{springThreadPoolTaskExecutor}"/>

Spring の `TaskExecutor` は非同期イベントのスケジューリングには対応しないため、 代替となる Seam `Dispatcher` を与えて次のようにスケジュールされた非同期イベントを処理することができます。

    <!-- Install a ThreadPoolDispatcher to handle scheduled asynchronous event -->

    <core:thread-pool-dispatcher name="threadPoolDispatcher"/>

    <!-- Install the SpringDispatcher as default -->

    <spring:task-executor-dispatcher task-executor="#{springThreadPoolTaskExecutor}" schedule-dispatcher="#{threadPoolDispatcher}"/>

- 前のページ第26章 SeamとGoogle Web Toolkit
- 上に戻る
- ホーム
- 次のページ第28章 Guice 統合