站内搜索: 请输入搜索关键词
当前页面: 在线文档首页 > JBoss Seam 1.2.0 正式版英文参考手册

Chapter 20. Spring Framework integration - JBoss Seam 1.2.0 正式版英文参考手册

Chapter 20. Spring Framework integration

The Spring integration module allows easy migration of Spring-based projects to Seam and allows Spring applications to take advantage of key Seam features like conversations and Seam's more sophisticated persistence context management.

Seam's support for Spring provides the ability to:

  • inject Seam component instances into Spring beans

  • inject Spring beans into Seam components

  • turn Spring beans into Seam components

  • allow Spring beans to live in any Seam context

20.1. Injecting Seam components into Spring beans

Injecting Seam component instances into Spring beans is accomplished using the <seam:instance/> namespace handler. To enable the Seam namespace handler, the Seam namespace must be added to the Spring beans definition file:

<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:seam="http://jboss.com/products/seam/spring"
    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 
                        http://jboss.com/products/seam/spring-1.2.xsd">

Now any Seam component may be injected into any Spring bean:

<bean id="someSpringBean" class="SomeSpringBeanClass" scope="prototype">
    <property name="someProperty">
        <seam:instance name="someComponent"/>
    </property>
</bean>

An EL expression may be used instead of a component name:

<bean id="someSpringBean" class="SomeSpringBeanClass" scope="prototype">
    <property name="someProperty">
        <seam:instance name="#{someExpression}"/>
    </property>
</bean>

Seam component instances may even be made available for injection into Spring beans by a Spring bean id.

<seam:instance name="someComponent" id="someSeamComponentInstance"/>

<bean id="someSpringBean" class="SomeSpringBeanClass" scope="prototype">
    <property name="someProperty" ref="someSeamComponentInstance">
</bean>

Now for the caveat!

Seam was designed from the ground up to support a stateful component model with multiple contexts. Spring was not. Unlike Seam bijection, Spring injection does not occur at method invocation time. Instead, injection happens only when the Spring bean is instantiated. So the instance available when the bean is instantiated will be the same instance that the bean uses for the entire life of the bean. For example, if a Seam CONVERSATION-scoped component instance is directly injected into a singleton Spring bean, that singleton will hold a reference to the same instance long after the conversation is over! We call this problem scope impedance. Seam bijection ensures that scope impedance is maintained naturally as an invocation flows through the system. In Spring, we need to inject a proxy of the Seam component, and resolve the reference when the proxy is invoked.

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>

This example shows one way to use a Seam-managed persistence context from a Spring bean. (A more robust way to use Seam-managed persistence contexts as a replacement for the Spring OpenEntityManagerInView filter will be provided in a future release)

20.2. Injecting Spring beans into Seam components

It is even easier to inject Spring beans into Seam component instances. Actually, there are two possible approaches:

  • inject a Spring bean using an EL expression

  • make the Spring bean a Seam component

We'll discuss the second option in the next section. The easiest approach is to access the Spring beans via EL.

The Spring DelegatingVariableResolver is an integration point Spring provides for integrating Spring with JSF. This VariableResolver makes all Spring beans available in EL by their bean id. You'll need to add the DelegatingVariableResolver to faces-config.xml:

<application>
    <variable-resolver>
        org.springframework.web.jsf.DelegatingVariableResolver
    </variable-resolver>
</application>

Then you can inject Spring beans using @In:

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

The use of Spring beans in EL is not limited to injection. Spring beans may be used anywhere that EL expressions are used in Seam: process and pageflow definitions, working memory assertions, etc...

20.3. Making a Spring bean into a Seam component

The <seam:component/> namespace handler can be used to make any Spring bean a Seam component. Just place the <seam:component/> tag within the declaration of the bean that you wish to be a Seam component:

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

By default, <seam:component/> will create a STATELESS Seam component with class and name provided in the bean definition. Occasionally, such as when a FactoryBean is used, the class of the Spring bean may not be the class appearing in the bean definition. In such cases the beanClass should be explicitly specified. A Seam component name may be explicitly specified in cases where there is potential for a naming conflict.

The scope attribute of <seam:component/> may be used if you wish the Spring bean to be managed in a particular Seam scope. The Spring bean must be scoped to prototype if the Seam scope specified is anything other than STATELESS. Pre-existing Spring beans usually have a fundamentally stateless character, so this attribute is not usually needed.

20.4. Seam-scoped Spring beans

The Seam integration package also lets you use Seam's contexts as Spring 2.0 style custom scopes. This lets you declare any Spring bean in any of Seam's contexts. However, note once again that Spring's component model was never architected to support statefulness, so please use this feature with great care. In particular, clustering of session or conversation scoped Spring beans is deeply problematic, and care must be taken when injecting a bean or component from a wider scope into a bean of a narrower scope.

By specifying <seam:configure-scopes/> once in a Spring bean factory configuration, all of the Seam scopes will be available to Spring beans as custom scopes. To associate a Spring bean with a particular Seam scope, specify the Seam scope in the scope attribute of the bean definition.

<!-- Only needs to be specified once per bean factory-->
<seam:configure-scopes/>

...

<bean id="someSpringBean" class="SomeSpringBeanClass" scope="seam.CONVERSATION"/>

The prefix of the scope name may be changed by specifying the prefix attribute in the configure-scopes definition. (The default prefix is seam.)

Seam-scoped Spring beans defined this way can be injected into other Spring beans without the use of <seam:instance/>. However, care must be taken to ensure scope impedance is maintained. The normal approach used in Spring is to specify <aop:scoped-proxy/> in the bean definition. However, Seam-scoped Spring beans are not compatible with <aop:scoped-proxy/>. So if you need to inject a Seam-scoped Spring bean into a singleton, <seam:instance/> must be used:

<bean id="someSpringBean" class="SomeSpringBeanClass" scope="seam.CONVERSATION"/>

...

<bean id="someSingleton">
    <property name="someSeamScopedSpringBean">
        <seam:instance name="someSpringBean" proxy="true"/>
    </property>
</bean>