sexta-feira, 20 de novembro de 2009

Integração Spring x JPA

Por Fábio Miranda, em 19 Fev 2008

Os primeiros parágrafos contém o "resumo da ópera". Em seguida, um pouco de código exemplificando as opções de integração.

DAOs que usam JPA necessitam de EntityManagerFactories (EMFs) e/ou EntityManagers (EMs) para realizar as operações num bancos de dados.

O Spring Framework gerencia objetos, podendo resolver dependências entre eles. Caso o Spring gerencie a(s) EMFs e os DAOs, ele pode injetar os EMFs nos DAOs, de forma transparente ao código. Então, a primeira coisa a se aprender é como fazer o Spring gerenciar a(s) EMF(s).

Uma vez configurados os beans necessários no Spring, pode-se partir para o código. É possível usar JPA com Spring de forma desacoplada, através de anotações JPA (desde que configure o Spring para reconhecer tais anotações); ou de forma acoplada, usando APIs especializadas do Spring.

DUMMY STEP) Para integrar JPA com Spring, logicamente é necessário um projeto JPA (grosso modo: entidades devidamente anotadas, e um arquivo META-INF/persistence.xml). Exemplo de projeto:

  • src
    • br.com.airframes
      • Product.java
    • META-INF
      • persistence.xml

1) Configuração recomendada da EMF (LocalContainerEntityManagerFactoryBean)

Esta maneira é a mais flexível e poderosa. A linha "load-time-weaver" refere-se a questões de instrumentação de código requeridas por alguns provedores de persistência. Não será necessária quando o provedor é o Hibernate, por isso deixei comentada.

Note que está comentada a linha da propriedade dataSource. Por default, o Spring usa as configurações de acesso ao banco presentes em persistence.xml. Porém, vc pode deixar que o Spring também gerencie o seu datasource (ignorando persistence.xml), conforme item 6 deste tutorial.

2) Declarar um DAO como bean do Spring, no qual será injetada a EMF:

3) Integração de Baixo acoplamento usando anotações (Plain JPA)

3.1) Para o Spring reconhecer as anotações JPA, declarar:

ou

3.2) Codificação do Dao

Pronto! Esta é a maneira mais poderosa de integrar Spring e JPA, sem que haja qualquer dependência ao Spring explícita no código Java. A Spring Framework desempenha seu papel de forma transparente, injetando o EntityManagerFactory num mecanismo possível graças a anotações e ao PersistenceAnnotationBeanPostProcessor.

4) Outras maneiras de o Spring gerenciar o EMF.

Há duas maneiras alternativas àquelas apresentadas no passo 1 deste tutorial:

4.1) No caso da aplicação rodar em um App Server, é preferível deixar o Spring localizar o EMF na árvore JNDI:

É necessário também cuidado especial com a instrumentação de código, de modo que ela não entre em conflito com as bibliotecas do App Server. (consultar documentação do Spring).

4.2) LocalEntityManagerFactoryBean ao invés de LocalContainerEntityManagerFactoryBean

É a forma mais simples porém mais limitada de integrar JPA ao Hibernate. Ela não dá suporte, por exemplo, a transações globais. Seu uso é recomendado em aplicações simples que usam apenas JPA para acessar dados. Pode ser muito útil em aplicações standalone e ambientes de teste.

5) Integração Altamente Acoplada ao Spring

Neste caso, lida-se com JpaTemplates no lugar de EntityManagers, pois JPATemplate encapsula o EntityManager (JPATemplate gerencia internamente o EntityManager, não expondo-o ao programador).

Desta forma, como o código Java deixará de usar a API EntityManager, deve-se:

- Remover as declarações do item 3.1 deste tutorial (annotations post processors).

- Reescrever a configuração do DAO, possibilitando injeção do EMF via setter:

- Escrever método setter no DAO possibilitando o Spring injetar a dependência:

Dispostas as linhas gerais, seguem as opções para este tipo de integração:

5.1) Declarar JpaTemplate explicitamente em cada DAO da aplicação

5.2) Herdar JpaDaoSupport

JpaSupportDao já fornece o jpaTemplate, e setter para injeção do EntityManagerFactory, sem que necessidade de escrever código redundante nos DAOs

5.3) E quando precisar acessar a EntityManager API diretamente?

Escrever subclasses de JpaCallback e executá-los em JpaTemplates. Ao fornecer um JpaCallback, JpaTemplate executará o método doInJpa(EntityManager em) passando como parâmetro a sua referência interna da EntityManager.

Essa abordagem possibilita ao programador acesso indireto à EntityManager (através de um Callback). Para não inchar o sistema com estas subclasses, é possível usar herança implícita no código.

O código abaixo reescreve doSomething com Callbacks que permitem acessar o EntityManager.

6) Datasource gerenciado pelo Spring

6.1) Spring localiza datasource no JNDI

6.2) Spring lida diretamente com datasource

(Usa DBCP como Pool de Conexões - pode ser substituída por outra segundo preferência - por exemplo o C3P0).

Para configurar um datasource na JNDI, é necessário consultar a documentação do app server / container web.

Para o Tomcat: Tomcat-JNDI HowTo.

A biblioteca Simple-Jndi permite implementar uma árvore JNDI em aplicações stand-alone (pode ser útil em casos de testes).

Bibliografia http://static.springframework.org/spring/docs/2.5.x/reference/orm.html#orm-jpa http://static.springframework.org/spring/docs/2.5.x/reference/jdbc.html

Um comentário:

  1. Olá Fábio,

    configurar o bean do DAO pode ser mais fácil. Ao invés de passar o EntityManager, podemos usar o Spring para se comportar como um container JPA e injetá-lo automaticamente.

    Veja http://blog.springsource.com/2006/08/07/using-jpa-in-spring-without-referencing-spring/

    Abraço,

    ..:: Thiago ::..

    ResponderExcluir