26.6. Using a Seam-Managed Persistence Context in Spring
Some of Seam's most powerful features are its conversation scope, and the ability to keep an
EntityManager
open for the life of a conversation. These eliminate many problems associated with detaching and reattaching entities, and mitigate the occurrence of LazyInitializationException
. Spring does not provide a way to manage persistence contexts beyond the scope of a single web request (OpenEntityManagerInViewFilter
).
Seam brings conversation-scoped persistence context capabilities to Spring applications by allowing Spring developers to access a Seam-managed persistence context with the JPA tools provided with Spring (
PersistenceAnnotationBeanPostProcessor
, JpaTemplate
, etc.)
This integration work provides:
- transparent access to a Seam-managed persistence context using Spring-provided tools
- access to Seam conversation-scoped persistence contexts in a non-web request — for example, an asynchronous Quartz job
- the ability to use Seam-managed persistence contexts with Spring-managed transactions. This requires manual flushing of the persistent context.
Spring's persistence context propagation model allows only one open
EntityManager
per EntityManagerFactory
, so the Seam integration works by wrapping an EntityManagerFactory
around a Seam-managed persistence context, like so:
<bean id="seamEntityManagerFactory" class="org.jboss.seam.ioc.spring.SeamManagedEntityManagerFactoryBean"> <property name="persistenceContextName" value="entityManager"/> </bean>
Here,
persistenceContextName
is the name of the Seam-managed persistence context component. By default, this EntityManagerFactory
has a unitName
equal to the Seam component name — in this case, entityManager
. If you wish to provide a different unitName
, you can provide a persistenceUnitName
like so:
<bean id="seamEntityManagerFactory" class="org.jboss.seam.ioc.spring.SeamManagedEntityManagerFactoryBean"> <property name="persistenceContextName" value="entityManager"/> <property name="persistenceUnitName" value="bookingDatabase:extended"/> </bean>
This
EntityManagerFactory
can now be used in any Spring-provided tools; in this case, you can use Spring's PersistenceAnnotationBeanPostProcessor
just as you would in Spring.
<bean class="org.springframework.orm.jpa.support .PersistenceAnnotationBeanPostProcessor"/>
If you define your real
EntityManagerFactory
in Spring, but wish to use a Seam-managed persistence context, you can tell the PersistenceAnnotationBeanPostProcessor
your desired default persistenctUnitName
by specifying the defaultPersistenceUnitName
property.
The
applicationContext.xml
might look like:
<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>
The
component.xml
might look like:
<persistence:managed-persistence-context name="entityManager" auto-create="true" entity-manager-factory="#{entityManagerFactory}"/>
JpaTemplate
and JpaDaoSupport
have an identical configuration in a Spring-based persistence context and in a normal Seam-managed persistence context.
<bean id="bookingService" class="org.jboss.seam.example.spring.BookingService"> <property name="entityManagerFactory" ref="seamEntityManagerFactory"/> </bean>