This appendix discusses some classic Spring usage patterns as a reference for developers maintaining legacy Spring applications. These usage patterns no longer reflect the recommended way of using these features and the current recommended usage is covered in the respective sections of the reference manual.
This section documents the classic usage patterns that you might encounter in a legacy Spring application. For the currently recommended usage patterns, please refer to the Chapter 14, 对象关系映射(ORM)数据访问 chapter.
For the currently recommended usage patterns for Hibernate see Section 14.3, “Hibernate”
The basic programming model for templating looks as follows, for methods that can be
part of any custom data access object or business service. There are no restrictions on
the implementation of the surrounding object at all, it just needs to provide a
Hibernate SessionFactory
. It can get the latter from anywhere, but preferably as bean
reference from a Spring IoC container - via a simple setSessionFactory(..)
bean
property setter. The following snippets show a DAO definition in a Spring container,
referencing the above defined SessionFactory
, and an example for a DAO method
implementation.
<beans> <bean id="myProductDao" class="product.ProductDaoImpl"> <property name="sessionFactory" ref="mySessionFactory"/> </bean> </beans>
public class ProductDaoImpl implements ProductDao { private HibernateTemplate hibernateTemplate; public void setSessionFactory(SessionFactory sessionFactory) { this.hibernateTemplate = new HibernateTemplate(sessionFactory); } public Collection loadProductsByCategory(String category) throws DataAccessException { return this.hibernateTemplate.find("from test.Product product where product.category=?", category); } }
The HibernateTemplate
class provides many methods that mirror the methods exposed on
the Hibernate Session
interface, in addition to a number of convenience methods such
as the one shown above. If you need access to the Session
to invoke methods that are
not exposed on the HibernateTemplate
, you can always drop down to a callback-based
approach like so.
public class ProductDaoImpl implements ProductDao { private HibernateTemplate hibernateTemplate; public void setSessionFactory(SessionFactory sessionFactory) { this.hibernateTemplate = new HibernateTemplate(sessionFactory); } public Collection loadProductsByCategory(final String category) throws DataAccessException { return this.hibernateTemplate.execute(new HibernateCallback() { public Object doInHibernate(Session session) { Criteria criteria = session.createCriteria(Product.class); criteria.add(Expression.eq("category", category)); criteria.setMaxResults(6); return criteria.list(); } }; } }
A callback implementation effectively can be used for any Hibernate data access.
HibernateTemplate
will ensure that Session
instances are properly opened and closed,
and automatically participate in transactions. The template instances are thread-safe
and reusable, they can thus be kept as instance variables of the surrounding class. For
simple single step actions like a single find, load, saveOrUpdate, or delete call,
HibernateTemplate
offers alternative convenience methods that can replace such one
line callback implementations. Furthermore, Spring provides a convenient
HibernateDaoSupport
base class that provides a setSessionFactory(..)
method for
receiving a SessionFactory
, and getSessionFactory()
and getHibernateTemplate()
for
use by subclasses. In combination, this allows for very simple DAO implementations for
typical requirements:
public class ProductDaoImpl extends HibernateDaoSupport implements ProductDao { public Collection loadProductsByCategory(String category) throws DataAccessException { return this.getHibernateTemplate().find( "from test.Product product where product.category=?", category); } }
As alternative to using Spring’s HibernateTemplate
to implement DAOs, data access code
can also be written in a more traditional fashion, without wrapping the Hibernate access
code in a callback, while still respecting and participating in Spring’s generic
DataAccessException
hierarchy. The HibernateDaoSupport
base class offers methods to
access the current transactional Session
and to convert exceptions in such a scenario;
similar methods are also available as static helpers on the SessionFactoryUtils
class.
Note that such code will usually pass false
as the value of the getSession(..)
methods allowCreate
argument, to enforce running within a transaction (which avoids
the need to close the returned Session
, as its lifecycle is managed by the
transaction).
public class HibernateProductDao extends HibernateDaoSupport implements ProductDao { public Collection loadProductsByCategory(String category) throws DataAccessException, MyException { Session session = getSession(false); try { Query query = session.createQuery("from test.Product product where product.category=?"); query.setString(0, category); List result = query.list(); if (result == null) { throw new MyException("No search results."); } return result; } catch (HibernateException ex) { throw convertHibernateAccessException(ex); } } }
The advantage of such direct Hibernate access code is that it allows any checked
application exception to be thrown within the data access code; contrast this to the
HibernateTemplate
class which is restricted to throwing only unchecked exceptions
within the callback. Note that you can often defer the corresponding checks and the
throwing of application exceptions to after the callback, which still allows working
with HibernateTemplate
. In general, the HibernateTemplate
class' convenience methods
are simpler and more convenient for many scenarios.
For the currently recommended usage patterns for JDO see Section 14.4, “JDO”
Each JDO-based DAO will then receive the PersistenceManagerFactory
through dependency
injection. Such a DAO could be coded against plain JDO API, working with the given
PersistenceManagerFactory
, but will usually rather be used with the Spring Framework’s
JdoTemplate
:
<beans> <bean id="myProductDao" class="product.ProductDaoImpl"> <property name="persistenceManagerFactory" ref="myPmf"/> </bean> </beans>
public class ProductDaoImpl implements ProductDao { private JdoTemplate jdoTemplate; public void setPersistenceManagerFactory(PersistenceManagerFactory pmf) { this.jdoTemplate = new JdoTemplate(pmf); } public Collection loadProductsByCategory(final String category) throws DataAccessException { return (Collection) this.jdoTemplate.execute(new JdoCallback() { public Object doInJdo(PersistenceManager pm) throws JDOException { Query query = pm.newQuery(Product.class, "category = pCategory"); query.declareParameters("String pCategory"); List result = query.execute(category); // do some further stuff with the result list return result; } }); } }
A callback implementation can effectively be used for any JDO data access. JdoTemplate
will ensure that PersistenceManager
s are properly opened and closed, and
automatically participate in transactions. The template instances are thread-safe and
reusable, they can thus be kept as instance variables of the surrounding class. For
simple single-step actions such as a single find
, load
, makePersistent
, or
delete
call, JdoTemplate
offers alternative convenience methods that can replace
such one line callback implementations. Furthermore, Spring provides a convenient
JdoDaoSupport
base class that provides a setPersistenceManagerFactory(..)
method for
receiving a PersistenceManagerFactory
, and getPersistenceManagerFactory()
and
getJdoTemplate()
for use by subclasses. In combination, this allows for very simple
DAO implementations for typical requirements:
public class ProductDaoImpl extends JdoDaoSupport implements ProductDao { public Collection loadProductsByCategory(String category) throws DataAccessException { return getJdoTemplate().find(Product.class, "category = pCategory", "String category", new Object[] {category}); } }
As alternative to working with Spring’s JdoTemplate
, you can also code Spring-based
DAOs at the JDO API level, explicitly opening and closing a PersistenceManager
. As
elaborated in the corresponding Hibernate section, the main advantage of this approach
is that your data access code is able to throw checked exceptions. JdoDaoSupport
offers a variety of support methods for this scenario, for fetching and releasing a
transactional PersistenceManager
as well as for converting exceptions.
For the currently recommended usage patterns for JPA see Section 14.5, “JPA”
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.
One of the benefits of Spring’s JMS support is to shield the user from differences between the JMS 1.0.2 and 1.1 APIs. (For a description of the differences between the two APIs see sidebar on Domain Unification). Since it is now common to encounter only the JMS 1.1 API the use of classes that are based on the JMS 1.0.2 API has been deprecated in Spring 3.0. This section describes Spring JMS support for the JMS 1.0.2 deprecated classes.
Located in the package org.springframework.jms.core
the class JmsTemplate102
provides all of the features of the JmsTemplate
described the JMS chapter, but is
based on the JMS 1.0.2 API instead of the JMS 1.1 API. As a consequence, if you are
using JmsTemplate102 you need to set the boolean property pubSubDomain
to configure
the JmsTemplate
with knowledge of what JMS domain is being used. By default the value
of this property is false, indicating that the point-to-point domain, Queues, will be
used.
MessageListenerAdapter’s are used in
conjunction with Spring’s message listener containers to support
asynchronous message reception by exposing almost any class as a Message-driven POJO. If
you are using the JMS 1.0.2 API, you will want to use the 1.0.2 specific classes such as
MessageListenerAdapter102
, SimpleMessageListenerContainer102
, and
DefaultMessageListenerContainer102
. These classes provide the same functionality as
the JMS 1.1 based counterparts but rely only on the JMS 1.0.2 API.
The ConnectionFactory
interface is part of the JMS specification and serves as the
entry point for working with JMS. Spring provides an implementation of the
ConnectionFactory
interface, SingleConnectionFactory102
, based on the JMS 1.0.2 API
that will return the same Connection
on all createConnection()
calls and ignore
calls to close()
. You will need to set the boolean property pubSubDomain
to indicate
which messaging domain is used as SingleConnectionFactory102
will always explicitly
differentiate between a javax.jms.QueueConnection
and a javax.jmsTopicConnection
.
In a JMS 1.0.2 environment the class JmsTransactionManager102
provides support for
managing JMS transactions for a single Connection Factory. Please refer to the reference
documentation on JMS Transaction Management for more information on this
functionality.