Integração entre Spring Framework e Hibernate: Configuração e Gerenciamento de Transações

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 SessionFactory do 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>

Tags: Spring-Framework hibernate java xml-configuration dependency-injection

Publicado em 6-3 22:07 por Thomas