Spring JPA (available under the
org.springframework.orm.jpa
package) offers
comprehensive support for the Java
Persistence API in a similar manner to the integration with
Hibernate or JDO, while being aware of the underlying implementation in
order to provide additional features.
Spring JPA offers three ways of setting up JPA
EntityManagerFactory
:
The LocalEntityManagerFactoryBean
creates
an EntityManagerFactory
suitable for
environments which solely use JPA for data access. The factory bean
will use the JPA PersistenceProvider
autodetection mechanism (according to JPA's Java SE bootstrapping)
and, in most cases, requires only the persistence unit name to be
specified:
<beans> <bean id="myEmf" class="org.springframework.orm.jpa.LocalEntityManagerFactoryBean"> <property name="persistenceUnitName" value="myPersistenceUnit"/> </bean> </beans>
This is the simplest but also most limited form of JPA
deployment. There is no way to link to an existing JDBC
DataSource
and no support for global
transactions, for example. Furthermore, weaving (byte-code
transformation) of persistent classes is provider-specific, often
requiring a specific JVM agent to specified on startup. All in all,
this option is only really sufficient for standalone applications and
test environments (which is exactly what the JPA specification
designed it for).
Only use this option in simple deployment environments like standalone applications and integration tests.
Obtaining an EntityManagerFactory
from JNDI (for example in a Java EE 5 environment), is just a matter
of changing the XML configuration:
<beans> <jee:jndi-lookup id="myEmf" jndi-name="persistence/myPersistenceUnit"/> </beans>
This assumes standard Java EE 5 bootstrapping, with the Java EE
server autodetecting persistence units (i.e.
META-INF/persistence.xml
files in application jars)
and persistence-unit-ref
entries in the Java EE
deployment descriptor (e.g. web.xml
) defining
environment naming context locations for those persistence
units.
In such a scenario, the entire persistence unit deployment,
including the weaving (byte-code transformation) of persistent
classes, is up to the Java EE server. The JDBC
DataSource
is defined through a JNDI
location in the META-INF/persistence.xml
file;
EntityManager transactions are integrated with the server's JTA
subsystem. Spring merely uses the obtained
EntityManagerFactory
, passing it on to
application objects via dependency injection, and managing
transactions for it (typically through
JtaTransactionManager
).
Note that, in case of multiple persistence units used in the
same application, the bean names of such a JNDI-retrieved persistence
units should match the persistence unit names that the application
uses to refer to them (e.g. in @PersistenceUnit
and
@PersistenceContext
annotations).
Use this option when deploying to a Java EE 5 server. Check your server's documentation on how to deploy a custom JPA provider into your server, allowing for a different provider than the server's default.
The
LocalContainerEntityManagerFactoryBean
gives
full control over EntityManagerFactory
configuration and is appropriate for environments where fine-grained
customization is required. The
LocalContainerEntityManagerFactoryBean
will
create a PersistenceUnitInfo
based on
the persistence.xml
file, the supplied
dataSourceLookup
strategy and the specified
loadTimeWeaver
. It is thus possible to work with
custom DataSources outside of JNDI and to control the weaving
process.
<beans> <bean id="myEmf" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"> <property name="dataSource" ref="someDataSource"/> <property name="loadTimeWeaver"> <bean class="org.springframework.instrument.classloading.InstrumentationLoadTimeWeaver"/> </property> </bean> </beans>
A typical persistence.xml
file looks as follows:
<persistence xmlns="http://java.sun.com/xml/ns/persistence" version="1.0"> <persistence-unit name="myUnit" transaction-type="RESOURCE_LOCAL"> <mapping-file>META-INF/orm.xml</mapping-file> <exclude-unlisted-classes/> </persistence-unit> </persistence>
NOTE: The "exclude-unlisted-classes" element always
indicates that NO scanning for annotated entity classes is supposed
to happen, in order to support the
<exclude-unlisted-classes/>
shortcut.
This is in line with the JPA specification (which suggests that shortcut)
but unfortunately in conflict with the JPA XSD (which implies "false"
for that shortcut). As a consequence,
"<exclude-unlisted-classes> false </exclude-unlisted-classes/>
"
is not supported! Simply omit the "exclude-unlisted-classes" element if
you would like entity class scanning to actually happen.
This is the most powerful JPA setup option, allowing for
flexible local configuration within the application. It supports links
to an existing JDBC DataSource
,
supports both local and global transactions, etc. However, it also
imposes requirements onto the runtime environment, such as the
availability of a weaving-capable ClassLoader if the persistence
provider demands byte-code transformation.
Note that this option may conflict with the built-in JPA
capabilities of a Java EE 5 server. So when running in a full Java EE
5 environment, consider obtaining your
EntityManagerFactory
from JNDI.
Alternatively, specify a custom "persistenceXmlLocation" on your
LocalContainerEntityManagerFactoryBean
definition, e.g. "META-INF/my-persistence.xml", and only include a
descriptor with that name in your application jar files. Since the
Java EE 5 server will only look for default
META-INF/persistence.xml
files, it will ignore such
custom persistence units and hence avoid conflicts with a
Spring-driven JPA setup upfront. (This applies to Resin 3.1, for
example.)
Use this option for full JPA capabilities in a Spring-based application environment. This includes web containers such as Tomcat as well as standalone applications and integration tests with sophisticated persistence requirements.
The LoadTimeWeaver
interface is a
Spring-provided class that allows JPA
ClassTransformer
instances to be
plugged in a specific manner depending on the environment (web
container/application server). Hooking
ClassTransformers
through a Java 5 agent
is typically not efficient - the agents work against the
entire virtual machine and inspect
every class that is loaded - something that is
typically undesirable in a production server enviroment.
Spring provides a number of
LoadTimeWeaver
implementations for
various environments, allowing
ClassTransformer
instances to be
applied only per ClassLoader and not per VM.
The following sections will discuss typical JPA weaving setup on Tomcat as well as using Spring's VM agent. See the AOP chapter section entitled Section 8.8.4.5, “Spring configuration” for details on how to set up general load-time weaving, covering Tomcat and the VM agent as well as WebLogic, OC4J, GlassFish and Resin.
Apache
Tomcat's default ClassLoader does not support class
transformation but allows custom ClassLoaders to be used. Spring
offers the TomcatInstrumentableClassLoader
(inside the
org.springframework.instrument.classloading.tomcat
package) which extends the Tomcat ClassLoader
(WebappClassLoader
) and allows JPA
ClassTransformer
instances to 'enhance' all
classes loaded by it. In short, JPA transformers will be applied
only inside a specific web application (which uses the
TomcatInstrumentableClassLoader
).
In order to use the custom ClassLoader on:
Copy spring-tomcat-weaver.jar
into
$CATALINA_HOME/server/lib (where
$CATALINA_HOME represents the root of the
Tomcat installation).
Instruct Tomcat to use the custom ClassLoader (instead of the default one) by editing the web application context file:
<Context path="/myWebApp" docBase="/my/webApp/location"> <Loader loaderClass="org.springframework.instrument.classloading.tomcat.TomcatInstrumentableClassLoader"/> </Context>
Tomcat 5.0.x and 5.5.x series support several context locations: server configuration file ($CATALINA_HOME/conf/server.xml), the default context configuration ($CATALINA_HOME/conf/context.xml) that affects all deployed web applications and per-webapp configurations, deployed on the server ($CATALINA_HOME/conf/[enginename]/[hostname]/my-webapp-context.xml) side or along with the webapp (your-webapp.war/META-INF/context.xml). For efficiency, inside the web-app configuration style is recommended since only applications which use JPA will use the custom ClassLoader. See the Tomcat 5.x documentation for more details about available context locations.
Note that versions prior to 5.5.20 contained a bug in
the XML configuration parsing preventing usage of
Loader
tag inside
server.xml (no matter if a ClassLoader is
specified or not (be it the official or a custom one). See
Tomcat's bugzilla for more
details.
If you are using Tomcat 5.5.20+ you can set
useSystemClassLoaderAsParent to
false
to fix the problem:
<Context path="/myWebApp" docBase="/my/webApp/location"> <Loader loaderClass="org.springframework.instrument.classloading.tomcat.TomcatInstrumentableClassLoader" useSystemClassLoaderAsParent="false"/> </Context>
Copy spring-tomcat-weaver.jar
into
$CATALINA_HOME/lib (where
$CATALINA_HOME represents the root of the
Tomcat installation).
Instruct Tomcat to use the custom ClassLoader (instead of the default one) by editing the web application context file:
<Context path="/myWebApp" docBase="/my/webApp/location"> <Loader loaderClass="org.springframework.instrument.classloading.tomcat.TomcatInstrumentableClassLoader"/> </Context>
Tomcat 6.0.x (similar to 5.0.x/5.5.x) series support several context locations: server configuration file ($CATALINA_HOME/conf/server.xml), the default context configuration ($CATALINA_HOME/conf/context.xml) that affects all deployed web applications and per-webapp configurations, deployed on the server ($CATALINA_HOME/conf/[enginename]/[hostname]/my-webapp-context.xml) side or along with the webapp (your-webapp.war/META-INF/context.xml). For efficiency, inside the web-app configuration style is recommended since only applications which use JPA will use the custom ClassLoader. See the Tomcat 5.x documentation for more details about available context locations.
Tomcat 5.0.x/5.5.x
Tomcat 6.0.x
The last step required on all Tomcat versions, is to use the
appropriate the LoadTimeWeaver
when
configuring
LocalContainerEntityManagerFactoryBean
:
<bean id="emf" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"> <property name="loadTimeWeaver"> <bean class="org.springframework.instrument.classloading.ReflectiveLoadTimeWeaver"/> </property> </bean>
Using this technique, JPA applications relying on instrumentation, can run in Tomcat without the need of an agent. This is important especially when hosting applications which rely on different JPA implementations since the JPA transformers are applied only at ClassLoader level and thus, are isolated from each other.
![]() | Note |
---|---|
If TopLink is being used a JPA provider under Tomcat, please place the toplink-essentials jar under $CATALINA_HOME/shared/lib folder instead of your war. |
For environments where class instrumentation is required but
are not supported by the existing LoadTimeWeaver implementations, a
JDK agent can be the only solution. For such cases, Spring provides
InstrumentationLoadTimeWeaver
which requires
a Spring-specific (but very general) VM agent (spring-agent.jar
):
<bean id="emf" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"> <property name="loadTimeWeaver"> <bean class="org.springframework.instrument.classloading.InstrumentationLoadTimeWeaver"/> </property> </bean>
Note that the virtual machine has to be started with the Spring agent, by supplying the following JVM options:
-javaagent:/path/to/spring-agent.jar
Since Spring 2.5, a context-wide LoadTimeWeaver
can be configured using the context:load-time-weaver
configuration
element. Such a 'global' weaver will be picked up by all JPA
LocalContainerEntityManagerFactoryBeans
automatically.
This is the preferred way of setting up a load-time weaver, delivering autodetection of the platform (WebLogic, OC4J, GlassFish, Tomcat, Resin, VM agent) as well as automatic propagation of the weaver to all weaver-aware beans.
<context:load-time-weaver/> <bean id="emf" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"> ... </bean>
See the section entitled Section 8.8.4.5, “Spring configuration” for details on how to set up general load-time weaving, covering Tomcat and the VM agent as well as WebLogic, OC4J, GlassFish and Resin.
For applications that rely on multiple persistence units
locations (stored in various jars in the classpath for example),
Spring offers the
PersistenceUnitManager
to act as a
central repository and avoid the (potentially expensive) persistence
units discovery process. The default implementation allows multiple
locations to be specified (by default, the classpath is searched for
'META-INF/persistence.xml'
files) which are
parsed and later on retrieved through the persistence unit
name:
<bean id="pum" class="org.springframework.orm.jpa.persistenceunit.DefaultPersistenceUnitManager"> <property name="persistenceXmlLocation"> <list> <value>org/springframework/orm/jpa/domain/persistence-multi.xml</value> <value>classpath:/my/package/**/custom-persistence.xml</value> <value>classpath*:META-INF/persistence.xml</value> </list> </property> <property name="dataSources"> <map> <entry key="localDataSource" value-ref="local-db"/> <entry key="remoteDataSource" value-ref="remote-db"/> </map> </property> <!-- if no datasource is specified, use this one --> <property name="defaultDataSource" ref="remoteDataSource"/> </bean> <bean id="emf" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"> <property name="persistenceUnitManager" ref="pum"/> </bean>
Note that the default implementation allows customization of the
persistence unit infos before feeding them to the JPA provider
declaratively through its properties (which affect all
hosted units) or programmatically, through the
PersistenceUnitPostProcessor
(which allows persistence unit selection). If no
PersistenceUnitManager
is
specified, one will be created and used internally by
LocalContainerEntityManagerFactoryBean
.
Each JPA-based DAO will then receive a
EntityManagerFactory
via dependency
injection. Such a DAO can be coded against plain JPA and work with the
given EntityManagerFactory
or through
Spring's JpaTemplate
:
<beans> <bean id="myProductDao" class="product.ProductDaoImpl"> <property name="entityManagerFactory" ref="myEmf"/> </bean> </beans>
public class JpaProductDao implements ProductDao { private JpaTemplate jpaTemplate; public void setEntityManagerFactory(EntityManagerFactory emf) { this.jpaTemplate = new JpaTemplate(emf); } public Collection loadProductsByCategory(final String category) throws DataAccessException { return (Collection) this.jpaTemplate.execute(new JpaCallback() { public Object doInJpa(EntityManager em) throws PersistenceException { Query query = em.createQuery("from Product as p where p.category = :category"); query.setParameter("category", category); List result = query.getResultList(); // do some further processing with the result list return result; } }); } }
The JpaCallback
implementation
allows any type of JPA data access. The
JpaTemplate
will ensure that
EntityManager
s are properly opened and
closed and automatically participate in transactions. Moreover, the
JpaTemplate
properly handles exceptions, making
sure resources are cleaned up and the appropriate transactions rolled
back. The template instances are thread-safe and reusable and they can
be kept as instance variable of the enclosing class. Note that
JpaTemplate
offers single-step actions such as
find, load, merge, etc along with alternative convenience methods that
can replace one line callback implementations.
Furthermore, Spring provides a convenient
JpaDaoSupport
base class that provides the
get/setEntityManagerFactory
and
getJpaTemplate()
to be used by
subclasses:
public class ProductDaoImpl extends JpaDaoSupport implements ProductDao { public Collection loadProductsByCategory(String category) throws DataAccessException { Map<String, String> params = new HashMap<String, String>(); params.put("category", category); return getJpaTemplate().findByNamedParams("from Product as p where p.category = :category", params); } }
Besides working with Spring's JpaTemplate
,
one can also code Spring-based DAOs against the JPA, doing one's own
explicit EntityManager
handling. As also
elaborated in the corresponding Hibernate section, the main advantage of
this approach is that your data access code is able to throw checked
exceptions. JpaDaoSupport
offers a variety of
support methods for this scenario, for retrieving and releasing a
transaction EntityManager
, as well as for
converting exceptions.
JpaTemplate mainly exists as a sibling of JdoTemplate
and HibernateTemplate, offering the same style for people used to it.
For newly started projects, consider adopting the native JPA style of
coding data access objects instead, based on a "shared EntityManager"
reference obtained through the JPA
@PersistenceContext
annotation (using Spring's
PersistenceAnnotationBeanPostProcessor
; see below
for details.)
![]() | Note |
---|---|
While |
It is possible to write code against the plain JPA without using
any Spring dependencies, using an injected
EntityManagerFactory
or
EntityManager
. Note that Spring can
understand @PersistenceUnit
and
@PersistenceContext
annotations both at
field and method level if a
PersistenceAnnotationBeanPostProcessor
is
enabled. A corresponding DAO implementation might look like this:
public class ProductDaoImpl implements ProductDao { private EntityManagerFactory emf; @PersistenceUnit public void setEntityManagerFactory(EntityManagerFactory emf) { this.emf = emf; } public Collection loadProductsByCategory(String category) { EntityManager em = this.emf.createEntityManager(); try { Query query = em.createQuery("from Product as p where p.category = ?1"); query.setParameter(1, category); return query.getResultList(); } finally { if (em != null) { em.close(); } } } }
The DAO above has no dependency on Spring and still fits nicely
into a Spring application context, just like it would if coded against
Spring's JpaTemplate
. Moreover, the DAO takes
advantage of annotations to require the injection of the default
EntityManagerFactory
:
<beans> <!-- bean post-processor for JPA annotations --> <bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor"/> <bean id="myProductDao" class="product.ProductDaoImpl"/> </beans>
Note: As alternative to defining a
PersistenceAnnotationBeanPostProcessor
explicitly, consider using Spring 2.5's
context:annotation-config
XML element in your
application context configuration. This will automatically register all
of Spring's standard post-processors for annotation-based configuration
(including CommonAnnotationBeanPostProcessor
etc).
<beans> <!-- post-processors for all standard config annotations --> <context:annotation-config/> <bean id="myProductDao" class="product.ProductDaoImpl"/> </beans>
The main issue with such a DAO is that it always creates a new
EntityManager
via the factory. This can
be easily overcome by requesting a transactional
EntityManager
(also called "shared
EntityManager", since it is a shared, thread-safe proxy for the actual
transactional EntityManager) to be injected instead of the
factory:
public class ProductDaoImpl implements ProductDao { @PersistenceContext private EntityManager em; public Collection loadProductsByCategory(String category) { Query query = em.createQuery("from Product as p where p.category = :category"); query.setParameter("category", category); return query.getResultList(); } }
Note that the @PersistenceContext
annotation
has an optional attribute type
, which defaults to
PersistenceContextType.TRANSACTION
. This default is
what you need to receive a "shared EntityManager" proxy. The
alternative, PersistenceContextType.EXTENDED
, is a
completely different affair: This results in a so-called "extended
EntityManager", which is not thread-safe and hence
must not be used in a concurrently accessed component such as a
Spring-managed singleton bean. Extended EntityManagers are only supposed
to be used in stateful components that, for example, reside in a
session, with the lifecycle of the EntityManager not tied to a current
transaction but rather being completely up to the application.
The injected EntityManager
is
Spring-managed (aware of the ongoing transaction). It is important to
note that even though the new implementation prefers method level
injection (of an EntityManager
instead of
an EntityManagerFactory)
, no change is
required in the application context XML due to annotation usage.
The main advantage of this DAO style is that it depends on Java Persistence API; no import of any Spring class is required. Moreover, as the JPA annotations are understood, the injections are applied automatically by the Spring container. This is of course appealing from a non-invasiveness perspective, and might feel more natural to JPA developers.
However, the DAO throws the plain
PersistenceException
exception class (which is
unchecked, and so does not have to be declared or caught) but also
IllegalArgumentException
and
IllegalStateException
, which means that callers
can only treat exceptions as generally fatal - unless they want to
depend on JPA's own exception structure. Catching specific causes such
as an optimistic locking failure is not possible without tying the
caller to the implementation strategy. This tradeoff might be acceptable
to applications that are strongly JPA-based and/or do not need any
special exception treatment. However, Spring offers a solution allowing
exception translation to be applied transparently through the
@Repository
annotation:
@Repository public class ProductDaoImpl implements ProductDao { // class body here... }
<beans> <!-- Exception translation bean post processor --> <bean class="org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor"/> <bean id="myProductDao" class="product.ProductDaoImpl"/> </beans>
The postprocessor will automatically look for all exception
translators (implementations of the
PersistenceExceptionTranslator
interface)
and advise all beans marked with the
@Repository
annotation so that the
discovered translators can intercept and apply the appropriate
translation on the thrown exceptions.
In summary: DAOs can be implemented based on the plain Java Persistence API and annotations, while still being able to benefit from Spring-managed transactions, dependency injection, and transparent exception conversion (if desired) to Spring's custom exception hierarchies.