Objetivos da Integração
A unificação do Spring Framework com o Hibernate visa resolver problemas de boilerplate e gerenciamento de recursos. Os dois objetivos arquiteturasi principaiss são:
- Delegar a criação e o gerenciamento do ciclo de vida da
SessionFactorydo Hibernate para o contêiner de Inversão de Controle (IoC) do Spring. - Substituir o controle manual de transações do Hibernate pelo modelo de transações declarativas do Spring, abstraindo a complexidade através de AOP (Programação Orientada a Aspectos).
Passo 1: Configuração Base do Hibernate
Na abordagem integrada, as credenciais de banco de dados e os mapeamentos de entidades são transferidos para o Spring. O arquivo hibernate.cfg.xml passa a conter apenas configurações específicas do motor de persistência, como dialeto e comportamento de log.
<?xml version="1.0" encoding="UTF-8"?>
<hibernate-configuration>
<session-factory>
<!-- Configurações específicas do Hibernate -->
<property name="hibernate.dialect">org.hibernate.dialect.MySQL8Dialect</property>
<property name="hibernate.show_sql">true</property>
<property name="hibernate.format_sql">true</property>
<property name="hibernate.hbm2ddl.auto">update</property>
<!-- Mapeamentos de classes agora gerenciados pelo Spring -->
</session-factory>
</hibernate-configuration>
As classes de entidade e seus respectivos arquivos de mapeamento (.hbm.xml) devem ser criados no pacote de domínio do projeto.
Passo 2: Configuração do Spring Framework
O Spring atua como a camada de infraestrutura, fornecendo o pool de conexões, a fábrica de sessões e o gerenciamento transacional.
1. Externalização das Propriedades do Banco de Dados
Crie um arquivo database.properties para isolar as configurações de conexão:
jdbc.driver=com.mysql.cj.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/sistema_db?useSSL=false&serverTimezone=UTC
jdbc.user=admin_sistema
jdbc.pass=senha_segura_123
pool.min=5
pool.max=50
pool.init=10
2. Configuração do DataSource e da SessionFactory
No arquivo de contexto do Spring (ex: applicationContext.xml), importe o arquivo de propriedades e configure o pool de conexões c3p0. Em seguida, injete o DataSource no LocalSessionFactoryBean.
<!-- Carregamento do arquivo de propriedades -->
<context:property-placeholder location="classpath:database.properties"/>
<!-- Configuração do Pool de Conexões -->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close">
<property name="driverClass" value="${jdbc.driver}"/>
<property name="jdbcUrl" value="${jdbc.url}"/>
<property name="user" value="${jdbc.user}"/>
<property name="password" value="${jdbc.pass}"/>
<property name="minPoolSize" value="${pool.min}"/>
<property name="maxPoolSize" value="${pool.max}"/>
<property name="initialPoolSize" value="${pool.init}"/>
</bean>
<!-- Fábrica de Sessões do Hibernate -->
<bean id="fabricaSessao" class="org.springframework.orm.hibernate5.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="configLocation" value="classpath:hibernate.cfg.xml"/>
<property name="mappingLocations" value="classpath:br/com/empresa/dominio/*.hbm.xml"/>
</bean>
3. Gerenciamento Declarativo de Transações
Para habilitar as transações declarativas, configure o HibernateTransactionManager, defina as regras transacionais via tx:advice e aplique-as aos serviços utilizando AOP.
<!-- Gerenciador de Transações -->
<bean id="gerenciadorTransacao" class="org.springframework.orm.hibernate5.HibernateTransactionManager">
<property name="sessionFactory" ref="fabricaSessao"/>
</bean>
<!-- Regras de Transação -->
<tx:advice id="regrasTransacionais" transaction-manager="gerenciadorTransacao">
<tx:attributes>
<tx:method name="buscar*" read-only="true"/>
<tx:method name="listar*" read-only="true"/>
<tx:method name="*" propagation="REQUIRED" rollback-for="Exception"/>
</tx:attributes>
</tx:advice>
<!-- Aplicação das regras via AOP -->
<aop:config>
<aop:pointcut id="pontoCorteServico" expression="execution(* br.com.empresa.servico.*.*(..))"/>
<aop:advisor advice-ref="regrasTransacionais" pointcut-ref="pontoCorteServico"/>
</aop:config>
Passo 3: Implementação da Camada de Persistência
Com a infreastrutura pronta, as classes DAO podem utilizar injeção de dependência para obter a SessionFactory. Recomenda-se o uso de injeção via construtor para garantir a imutabilidade das dependências.
package br.com.empresa.persistencia;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.springframework.stereotype.Repository;
@Repository
public class UsuarioDao {
private final SessionFactory fabricaSessao;
public UsuarioDao(SessionFactory fabricaSessao) {
this.fabricaSessao = fabricaSessao;
}
private Session obterSessaoAtual() {
return fabricaSessao.getCurrentSession();
}
public void exibirDadosUsuario(String id) {
Usuario usuario = obterSessaoAtual().get(Usuario.class, id);
if (usuario != null) {
System.out.println("Nome do Usuário: " + usuario.getNomeCompleto());
} else {
System.out.println("Usuário não encontrado.");
}
}
}
Habilite a varredura de componentes no arquivo XML do Spring:
<context:component-scan base-package="br.com.empresa"/>
Passo 4: Execução e Teste
A classe principal carrega o contexto do Spring e recupera o bean do DAO para executar as operações de banco de dados.
package br.com.empresa;
import br.com.empresa.persistencia.UsuarioDao;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class AplicacaoPrincipal {
public static void main(String[] args) {
ApplicationContext contexto = new ClassPathXmlApplicationContext("applicationContext.xml");
UsuarioDao usuarioDao = contexto.getBean(UsuarioDao.class);
usuarioDao.exibirDadosUsuario("USR-992");
}
}
Arquivo de Configuração Completo do Spring
Abaixo está a estrutura unificada do arquivo applicationContext.xml:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd">
<context:component-scan base-package="br.com.empresa"/>
<context:property-placeholder location="classpath:database.properties"/>
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close">
<property name="driverClass" value="${jdbc.driver}"/>
<property name="jdbcUrl" value="${jdbc.url}"/>
<property name="user" value="${jdbc.user}"/>
<property name="password" value="${jdbc.pass}"/>
<property name="minPoolSize" value="${pool.min}"/>
<property name="maxPoolSize" value="${pool.max}"/>
<property name="initialPoolSize" value="${pool.init}"/>
</bean>
<bean id="fabricaSessao" class="org.springframework.orm.hibernate5.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="configLocation" value="classpath:hibernate.cfg.xml"/>
<property name="mappingLocations" value="classpath:br/com/empresa/dominio/*.hbm.xml"/>
</bean>
<bean id="gerenciadorTransacao" class="org.springframework.orm.hibernate5.HibernateTransactionManager">
<property name="sessionFactory" ref="fabricaSessao"/>
</bean>
<tx:advice id="regrasTransacionais" transaction-manager="gerenciadorTransacao">
<tx:attributes>
<tx:method name="buscar*" read-only="true"/>
<tx:method name="*" propagation="REQUIRED" rollback-for="Exception"/>
</tx:attributes>
</tx:advice>
<aop:config>
<aop:pointcut id="pontoCorteServico" expression="execution(* br.com.empresa.servico.*.*(..))"/>
<aop:advisor advice-ref="regrasTransacionais" pointcut-ref="pontoCorteServico"/>
</aop:config>
</beans>
Abordagem Alternativa: Propriedades Inline
Embora o uso de um arquivo hibernate.cfg.xml separado seja o padrão, é possível consolidar todas as configurações diretamente no bean da SessionFactory do Spring utilizando a propriedade hibernateProperties. Isso elimina a necessidade do arquivo XML do Hibernate.
<bean id="fabricaSessao" class="org.springframework.orm.hibernate5.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="mappingLocations" value="classpath:br/com/empresa/dominio/*.hbm.xml"/>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.PostgreSQLDialect</prop>
<prop key="hibernate.show_sql">false</prop>
<prop key="hibernate.hbm2ddl.auto">validate</prop>
</props>
</property>
</bean>