Exemplo de Tutorial de Integração Spring Hibernate (Spring 4 + Hibernate 3 e Hibernate 4)

Spring é um dos frameworks Java EE mais utilizados e Hibernate é o framework ORM mais popular. É por isso que a combinação Spring Hibernate é muito utilizada em aplicações empresariais. Recentemente, tenho escrito muito sobre Tutorial Spring e Tutorial Hibernate, então um post sobre integração spring hibernate era necessário há muito tempo.

Spring Hibernate

Hoje neste tutorial, vamos usar o Spring 4 e integrá-lo com o Hibernate 3 e depois atualizar o mesmo projeto para usar o Hibernate 4. Como existem muitas versões tanto para o Spring quanto para o Hibernate e o artefato Spring ORM suporta tanto o Hibernate 3 quanto o Hibernate 4, é bom que eu liste todas as dependências que utilizei no meu projeto. Note que observei que nem todas as versões do Spring e do Hibernate são compatíveis, as versões abaixo funcionaram para mim, então acredito que sejam compatíveis. Se estiver usando outras versões e receber java.lang.NoClassDefFoundError, significa que elas não são compatíveis. Na maioria das vezes, isso ocorre porque as classes do Hibernate são movidas de um pacote para outro, causando esse erro. Por exemplo, a classe org.hibernate.engine.FilterDefinition foi movida para org.hibernate.engine.spi.FilterDefinition nas versões mais recentes do Hibernate.

  • Versão do Spring Framework: 4.0.3.RELEASE
  • Versão do Hibernate Core e do Hibernate EntityManager: 3.6.9.Final e 4.3.5.Final
  • Versão do Spring ORM: 4.0.3.RELEASE

Configuração do Banco de Dados

I am using MySQL database for my project, so below setup.sql script will create the necessary table for this example.

CREATE TABLE `Person` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `name` varchar(20) NOT NULL DEFAULT '',
  `country` varchar(20) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8;
commit;

Estrutura do Projeto de Exemplo de Integração Spring Hibernate

Abaixo, a imagem mostra a estrutura final do projeto. Vamos analisar cada um dos componentes um por um.

Dependências do Maven

Primeiramente, examinaremos nosso arquivo pom.xml para todas as dependências necessárias e suas versões.

<project xmlns="https://maven.apache.org/POM/4.0.0" xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="https://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<groupId>org.springframework.samples</groupId>
	<artifactId>SpringHibernateExample</artifactId>
	<version>0.0.1-SNAPSHOT</version>

	<properties>

		<!-- Generic properties -->
		<java.version>1.6</java.version>
		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
		<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>

		<!-- Spring -->
		<spring-framework.version>4.0.3.RELEASE</spring-framework.version>

		<!-- Hibernate / JPA -->
		<!-- <hibernate.version>4.3.5.Final</hibernate.version> -->
		<hibernate.version>3.6.9.Final</hibernate.version>

		<!-- Logging -->
		<logback.version>1.0.13</logback.version>
		<slf4j.version>1.7.5</slf4j.version>

	</properties>

	<dependencies>
		<!-- Spring and Transactions -->
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-context</artifactId>
			<version>${spring-framework.version}</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-tx</artifactId>
			<version>${spring-framework.version}</version>
		</dependency>

		<!-- Spring ORM support -->
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-orm</artifactId>
			<version>${spring-framework.version}</version>
		</dependency>

		<!-- Logging with SLF4J & LogBack -->
		<dependency>
			<groupId>org.slf4j</groupId>
			<artifactId>slf4j-api</artifactId>
			<version>${slf4j.version}</version>
			<scope>compile</scope>
		</dependency>
		<dependency>
			<groupId>ch.qos.logback</groupId>
			<artifactId>logback-classic</artifactId>
			<version>${logback.version}</version>
			<scope>runtime</scope>
		</dependency>

		<!-- Hibernate -->
		<dependency>
			<groupId>org.hibernate</groupId>
			<artifactId>hibernate-entitymanager</artifactId>
			<version>${hibernate.version}</version>
		</dependency>
		<dependency>
			<groupId>org.hibernate</groupId>
			<artifactId>hibernate-core</artifactId>
			<version>${hibernate.version}</version>
		</dependency>

		<dependency>
			<groupId>mysql</groupId>
			<artifactId>mysql-connector-java</artifactId>
			<version>5.1.9</version>
		</dependency>
		<dependency>
			<groupId>commons-dbcp</groupId>
			<artifactId>commons-dbcp</artifactId>
			<version>1.4</version>
		</dependency>
	</dependencies>
</project>

Dependências importantes para o projeto de integração Spring e Hibernate são:

  • spring-context e spring-tx para funcionalidades essenciais do Spring. Observe que estou usando a versão 4.0.3.RELEASE.
  • spring-orm para suporte ao ORM do Spring, é necessário para a integração do Hibernate em nosso projeto Spring.
  • hibernate-entitymanager e hibernate-core para o framework Hibernate. Observe que a versão é 3.6.9.Final; para usar o Hibernate 4, basta alterar para 4.3.5.Final, conforme comentado no arquivo pom.xml acima.
  • mysql-connector-java para o driver MySQL para conexão com o banco de dados.

Classe de Modelo ou Entidade

Podemos usar o mapeamento baseado em XML do Hibernate, bem como o mapeamento baseado em anotações JPA. Aqui estou usando as anotações JPA para o mapeamento porque o Hibernate fornece uma implementação JPA.

package com.journaldev.model;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;

/**
 * Entity bean with JPA annotations
 * Hibernate provides JPA implementation
 * @author pankaj
 *
 */
@Entity
@Table(name="Person")
public class Person {

	@Id
	@Column(name="id")
	@GeneratedValue(strategy=GenerationType.IDENTITY)
	private int id;
	
	private String name;
	
	private String country;

	public int getId() {
		return id;
	}

	public void setId(int id) {
		this.id = id;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public String getCountry() {
		return country;
	}

	public void setCountry(String country) {
		this.country = country;
	}
	
	@Override
	public String toString(){
		return "id="+id+", name="+name+", country="+country;
	}
}

Classes DAO

Iremos implementar dois métodos em nossas classes DAO, o primeiro para salvar o objeto Pessoa na tabela e o segundo que irá buscar todos os registros da tabela e retornar a lista de Pessoas.

package com.journaldev.dao;

import java.util.List;

import com.journaldev.model.Person;

public interface PersonDAO {

	public void save(Person p);
	
	public List<Person> list();
	
}

A implementação da classe DAO acima seria como abaixo.

package com.journaldev.dao;

import java.util.List;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;

import com.journaldev.model.Person;

public class PersonDAOImpl implements PersonDAO {

	private SessionFactory sessionFactory;

    public void setSessionFactory(SessionFactory sessionFactory) {
        this.sessionFactory = sessionFactory;
    }
    
	@Override
	public void save(Person p) {
		Session session = this.sessionFactory.openSession();
		Transaction tx = session.beginTransaction();
		session.persist(p);
		tx.commit();
		session.close();
	}

	@SuppressWarnings("unchecked")
	@Override
	public List<Person> list() {
		Session session = this.sessionFactory.openSession();
		List<Person> personList = session.createQuery("from Person").list();
		session.close();
		return personList;
	}

}

Observe que este é o único lugar onde estamos usando classes relacionadas ao Hibernate. Este padrão torna nossa implementação flexível e fácil de migrar de uma tecnologia para outra. Por exemplo, se quisermos usar o framework ORM iBatis, tudo o que precisamos fazer é fornecer uma implementação DAO para o iBatis e, em seguida, alterar o arquivo de configuração do bean do Spring. No exemplo acima, estou usando o gerenciamento de transações de sessão do Hibernate. Mas também podemos usar o gerenciamento de transações declarativo do Spring usando a anotação @Transactional, leia mais em Gerenciamento de Transações do Spring.

Arquivo de Configuração de Beans do Spring para Integração do Hibernate 3

Vamos primeiro analisar as configurações de bean de spring que precisamos para integração com o Hibernate 3, vamos nos aprofundar mais tarde.

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="https://www.springframework.org/schema/beans"
	xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance" xmlns:aop="https://www.springframework.org/schema/aop"
	xmlns:tx="https://www.springframework.org/schema/tx"
	xsi:schemaLocation="https://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd
		https://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop-4.0.xsd
		https://www.springframework.org/schema/tx https://www.springframework.org/schema/tx/spring-tx-4.0.xsd">

	<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"
		destroy-method="close">
		<property name="driverClassName" value="com.mysql.jdbc.Driver" />
		<property name="url" value="jdbc:mysql://localhost:3306/TestDB" />
		<property name="username" value="pankaj" />
		<property name="password" value="pankaj123" />
	</bean>

<!-- Hibernate 3 XML SessionFactory Bean definition-->
<!-- 	<bean id="hibernate3SessionFactory"
		class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
		<property name="dataSource" ref="dataSource" />
		<property name="mappingResources">
			<list>
				<value>person.hbm.xml</value>
			</list>
		</property>
		<property name="hibernateProperties">
			<value>
				hibernate.dialect=org.hibernate.dialect.MySQLDialect
			</value>
		</property>
	</bean> -->

<!-- Hibernate 3 Annotation SessionFactory Bean definition-->
	<bean id="hibernate3AnnotatedSessionFactory"
		class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
		<property name="dataSource" ref="dataSource" />
		<property name="annotatedClasses">
			<list>
				<value>com.journaldev.model.Person</value>
			</list>
		</property>
		<property name="hibernateProperties">
			<props>
				<prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
				<prop key="hibernate.current_session_context_class">thread</prop>
				<prop key="hibernate.show_sql">false</prop>
			</props>
		</property>
	</bean>
	
	<bean id="personDAO" class="com.journaldev.dao.PersonDAOImpl">
		<property name="sessionFactory" ref="hibernate3AnnotatedSessionFactory" />
	</bean>
</beans>

Existem duas maneiras pelas quais podemos fornecer detalhes de conexão com o banco de dados ao Hibernate, primeiro passando tudo em hibernateProperties e segundo criando um DataSource e então passando-o para o Hibernate. Prefiro a segunda abordagem, por isso temos a dependência do Apache Commons DBCP para criar um BasicDataSource configurando as propriedades de conexão com o banco de dados. Para integração com Spring e Hibernate 3, Spring ORM fornece duas classes – org.springframework.orm.hibernate3.LocalSessionFactoryBean quando os mapeamentos do Hibernate são baseados em XML e org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean para mapeamento baseado em anotações. Eu forneci uma configuração de bean simples de LocalSessionFactoryBean em comentários, se estiver usando mapeamentos baseados em XML. AnnotationSessionFactoryBean estende a classe LocalSessionFactoryBean, então ela tem todas as propriedades básicas para integração com o Hibernate. As propriedades são autoexplicativas e principalmente relacionadas ao Hibernate, então não vou me aprofundar muito nelas. Mas se você estiver se perguntando de onde vêm hibernateProperties, annotatedClasses, você precisa olhar o código-fonte da classe de bean. Observe a definição do bean de personDAO, como mencionei anteriormente, se precisarmos mudar para algum outro framework ORM, precisamos alterar a classe de implementação aqui e definir quaisquer outras propriedades que precisamos.

Programa de Teste do Spring 4 Hibernate 3

Nossa configuração está pronta agora, vamos escrever um programa simples para testar nossa aplicação.

package com.journaldev.main;

import java.util.List;

import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.journaldev.dao.PersonDAO;
import com.journaldev.model.Person;

public class SpringHibernateMain {

	public static void main(String[] args) {

		ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");
		
		PersonDAO personDAO = context.getBean(PersonDAO.class);
		
		Person person = new Person();
		person.setName("Pankaj"); person.setCountry("India");
		
		personDAO.save(person);
		
		System.out.println("Person::"+person);
		
		List list = personDAO.list();
		
		for(Person p : list){
			System.out.println("Person List::"+p);
		}
		//fechar recursos
		context.close();	
	}
}

Ao executarmos o programa acima, obtemos muita saída relacionada ao Hibernate porque não configurei o registro adequadamente, mas isso está fora do escopo deste tutorial. No entanto, obtemos a seguinte saída gerada por nosso programa.

Person::id=3, name=Pankaj, country=India
Person List::id=1, name=Pankaj, country=India
Person List::id=2, name=Pankaj, country=India
Person List::id=3, name=Pankaj, country=India

Alterações na integração do Spring 4 Hibernate 4

Agora vamos alterar nossa aplicação para usar o Hibernate 4 em vez do Hibernate 3. Para esta migração, precisamos fazer apenas as seguintes alterações de configuração.

  1. Altere a versão do hibernate para 4.3.5.Final no arquivo pom.xml, conforme mostrado nos comentários acima.

  2. Altere o arquivo de configuração do Spring Bean. Até agora, você deve ter percebido que o arquivo de configuração do Spring Bean é a chave para a integração do framework Spring com o Hibernate. O arquivo de configuração do Spring Bean abaixo funcionará para as versões Spring 4 e Hibernate 4.

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="https://www.springframework.org/schema/beans"
    	xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance" xmlns:aop="https://www.springframework.org/schema/aop"
    	xmlns:tx="https://www.springframework.org/schema/tx"
    	xsi:schemaLocation="https://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd
    		https://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop-4.0.xsd
    		https://www.springframework.org/schema/tx https://www.springframework.org/schema/tx/spring-tx-4.0.xsd">
    
    	<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"
    		destroy-method="close">
    		<property name="driverClassName" value="com.mysql.jdbc.Driver" />
    		<property name="url" value="jdbc:mysql://localhost:3306/TestDB" />
    		<property name="username" value="pankaj" />
    		<property name="password" value="pankaj123" />
    	</bean>
    
    	<!-- Definição do Bean Hibernate 4 SessionFactory -->
    	<bean id="hibernate4AnnotatedSessionFactory"
    		class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
    		<property name="dataSource" ref="dataSource" />
    		<property name="annotatedClasses">
    			<list>
    				<value>com.journaldev.model.Person</value>
    			</list>
    		</property>
    		<property name="hibernateProperties">
    			<props>
    				<prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
    				<prop key="hibernate.current_session_context_class">thread</prop>
    				<prop key="hibernate.show_sql">false</prop>
    			</props>
    		</property>
    	</bean>
    
    	<bean id="personDAO" class="com.journaldev.dao.PersonDAOImpl">
    		<property name="sessionFactory" ref="hibernate4AnnotatedSessionFactory" />
    	</bean>
    </beans>
    

    Para o Hibernate 4, precisamos usar org.springframework.orm.hibernate4.LocalSessionFactoryBean para o bean SessionFactory. O Spring ORM fundiu ambas as classes para o Hibernate 3, agora há uma única classe, o que é bom para evitar confusão. Todas as outras configurações são as mesmas que antes.

É isso, nosso projeto foi migrado com sucesso para o Hibernate 4, legal não é? Apenas altere a classe SpringHibernateMain para usar spring4.xml para a configuração dos beans e funcionará bem, você obterá a mesma saída que antes. Você pode baixar o projeto final pelo link abaixo e brincar com mais configurações para aprender mais.

Baixe o Projeto de Integração Spring Hibernate

Source:
https://www.digitalocean.com/community/tutorials/spring-hibernate-integration-example-tutorial