Spring

Spring is another popular context that is used by many Java developers because it simplifies application development by offering capabilities such as dependency injection and aspect-oriented programming (AOP). Spring is a lightweight context, but it doesn't implement the JEE specifications, so it's not a Java enterprise container.

Note

Spring used to be known simply as a context, but the current direction of Spring is, in fact, moving towards being a standalone container, so enterprise applications can be written without having to implement JEE specifications. Spring now offers a Model-view-controller framework, web services, Spring data, batch, Spring integration, and many other capabilities, which collectively make Spring a worthy competitor to JEE. Nevertheless, Spring plays very nicely in JEE containers while simplifying many configuration and deployment tasks.

In this section, we will discuss how to configure Hibernate using the Spring container. If you are new to Spring, we highly recommend that you refer to the user guides available online.

Configuration

In a typical Spring application, the Hibernate session factory is declared as a Spring bean, which is then injected into various Data Access Objects. (DAO) classes. Furthermore, this allows you to inject other resources, such as a data source and transaction manager, into the Hibernate session factory. To declare the Hibernate session factory as a Spring bean, you'll have to use a wrapper class, as shown here:

<bean id="sessionFactory"
  class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
    <property name="dataSource" ref="dataSourceJndi" />
    <property name="jtaTransactionManager" ref="transactionManager"/>
    <property name="configLocation"
              value="classpath:hibernate-spring.cfg.xml" />
    <property name="packagesToScan"
              value="com.packt.hibernate.ch9.model" />
</bean>

The wrapper class is included in the Spring ORM library, which includes support for different versions of Hibernate. Another thing to note is that we will use a data source that is configured by the app server. You can declare the data source bean, like this:

<jee:jndi-lookup id="dataSourceJndi" 
        jndi-name="java:jboss/datasources/postgresDS"/>

Also, note that, for this example, we will use the JTA transaction manager provided by the app server, which can be declared like this:

<bean id="transactionManager"
  class="org.springframework.transaction.jta.JtaTransactionManager"/>

<tx:jta-transaction-manager
  transaction-manager="transactionManager"/> 

The Hibernate entities can be discovered by the packagesToScan property. And finally, you can declare additional Hibernate properties in a separate configuration file and allow Spring to further configure Hibernate using that file. This property is the typical configuration file that you would use with a standalone Hibernate application:

<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE hibernate-configuration PUBLIC
        "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
        "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
  <session-factory>
    <property 
           name="dialect">org.hibernate.dialect.PostgreSQLDialect</property>
    <property name="hbm2ddl.auto">update</property>
    <property name="current_session_context_class">jta</property>
    <property name="show_sql">true</property>
    <property name="format_sql">true</property>
  </session-factory>
</hibernate-configuration>

Transaction management

When working with Spring, you can decorate your service methods (or DAO methods) with the @Transactional annotation to demarcate transactions. Spring will then participate in a global transaction and commit or rollback accordingly.

In the case of global transactions, the transaction coordinator (typically, the application server) manages the life cycle of a transaction. Spring is still at the mercy of JTA because of the two-phase commit; when multiple transactional resources are part of the unit of work, the transaction coordinator will decide to commit or roll back the global transaction.

However, Hibernate also needs to know about the transaction manager because Hibernate Session requires a transactional context. This is facilitated by Spring. The transactionManager Spring bean, which we saw earlier, is responsible for discovering the provided JTA manager, and that is done through the JNDI lookup. And as you saw, this transaction manager bean is wired to the Hibernate session factory through the session factory wrapper.

If you are using a local transaction, Spring can still begin and commit/rollback transactions for you. In that case, simply change the transaction manager to the local transaction, shown here:

<bean id="transactionManager"
  class="org.springframework.orm.hibernate4.HibernateTransactionManager">
  <property name="sessionFactory" ref="sessionFactory" />
</bean>

Data source

The configuration example shown earlier, uses the data source and connection pool that is configured on the application server. If the application server does not manage the data source, Spring can create and manage one for your application. An example is shown here:

<bean id="myDS" class="org.apache.commons.dbcp2.BasicDataSource"
        destroy-method="close">
    <property name="driverClassName" value="org.postgresql.Driver" />
    <property name="url" 
        value="jdbc:postgresql://localhost:5432/packtdb" />
    <property name="username" value="dbuser" />
    <property name="password" value="password" />
</bean>

Session factory

Working with Hibernate session in the Spring context is similar to working with Entity Manager in the EJB context. However, Spring can only wire the session factory class, you still need to obtain a session from the factory.

A typical DAO class may look like the one shown here:

public class PersonDAOImpl implements PersonDAO {    
    private SessionFactory sessionFactory;

    public PersonDAOImpl(SessionFactory sessionFactory) {
        this.sessionFactory = sessionFactory;
    }
    
    @SuppressWarnings("unchecked")
    @Override
    @Transactional
    public List<Person> list() {
        return sessionFactory.getCurrentSession()
                .createCriteria(Person.class)
                .addOrder(Order.asc("id"))
                .setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY)
                .list();
    }

    @Override
    @Transactional
    public Person findById(long personId) {
        return (Person) sessionFactory.getCurrentSession().get(Person.class, personId);
    }

    @Override
    @Transactional
    public void save(Person person) {
        sessionFactory.getCurrentSession().save(person);
    }
    
    @Override
    @Transactional
    public void update(Person person) {
        sessionFactory.getCurrentSession().saveOrUpdate(person);
    }

    @Override
    @Transactional
    public void delete(long personId) {
        Person person = (Person) sessionFactory.getCurrentSession().get(Person.class, personId);
        sessionFactory.getCurrentSession().delete(person);
    }
}

The first thing to note is that the session factory is provided by Spring through dependency injection. In your Spring configuration file, you will need to declare this class as a Spring bean and then wire in the session factory, as shown here:

<bean id="personDao" class="com.packt.hibernate.dao.PersonDAOImpl">
  <constructor-arg>
    <ref bean="sessionFactory" />
  </constructor-arg>
</bean>

Next, note that the methods of this DAO class are annotated as transactional. When Spring encounters this, it will ensure that a transaction has started before calling this method.

Note

Typically, a Spring application has a Service layer and a DAO layer. The service layer is where the business logic is implemented, and within that logic, you may need to connect to multiple transactional resources, and each service method is typically considered a unit of work. This is why the transaction is demarcated in the service layer, so you will annotate the service method as transactional and that transaction will propagate to the DAO layer. This example doesn't have a service layer since it's a simple Create, Read, Update, Delete (CRUD) application.

Finally, note that you still have to obtain a session from the session factory because what is injected is the factory class.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.227.26.217