O Java Database Connectivity (JDBC) é uma conhecida API que fornece um conjunto de recursos que podem ser usados no inter-relacionamento entre aplicações Java e uma grande quantidade de banco de dados SQL. A persistência de dados em Java através do uso do JDBC sempre foi uma tarefa trabalhosa para o desenvolvedor porque a maior parte dos bancos de dados em uso no mercado funcionam no paradigma relacional, no entanto, as aplicações Java são desenvolvidas no paradigma orientado a objetos, o que ocasiona durante o processo de relacionamento entre esses dois paradigmas um considerável problema, ao qual se dá o nome de Descasamento de Impedância.
Porém, com o uso da JPA esse problema torna-se transparente, fornecendo ao desenvolvedor uma API que fornece suporte ao mapeamento objeto relacional através do uso de metadados dentro do código da aplicação.
A especificação JPA é reconhecidamente uma das mais usadas estratégias de persistência de dados no mundo Java, isso porque ela proporciona um conjunto de recursos que visão facilitar o desenvolvimento das atividades de persistência. Tem como destaque o mapeamento objeto/relacional, que proporciona o mapeamento da base de dados através de anotações usadas no próprio código fonte da aplicação. O Spring é um framework que tem o objetivo de simplificar o desenvolvimento de projetos Java através de diversos recursos por ele oferecidos, tais como injeção de dependência, gerenciamento de transação, integração com várias tecnologias, etc. Juntos, esses dois recursos tornarão a sua experiência como desenvolvedor muito mais simples, abstraindo grande parte da complexidade envolvida no processo de desenvolvimento de aplicações Java. A seguir os conheceremos melhor e como integrá-los.
API JPA
O Java Persistence API (JPA) é uma especificação da plataforma Java EE representada pela JSR-000338. Ela fornece ao desenvolvedor uma grande facilidade na realização de mapeamentos objeto-relacional e também no gerenciamento de dados relacionais em aplicações Java. O JPA é formado por quatro áreas:
- A API Java Persistence,
- A linguagem de consulta (JPQL),
- A API Criteria e
- Metadados para mapeamento objeto relacional.
Uma das grandes vantagens da JPA é o fato desta especificação não estar vinculada a apenas uma implementação, ou seja, existem diversas implementações disponíveis no mercado, o que permite escolher a que preferir, não o deixando preso a um fornecedor específico. Duas das mais utilizadas são as disponibilizadas pelos projetos Hibernate e EclipseLink (seção Links), ambas implementadas dentro da especificação fornecida pela Oracle.
Outra vantagem que podemos destacar é o fato dela poder ser utilizada em conjunto com outras tecnologias, inclusive as que não fazem parte da plataforma Java EE, como é o caso do Spring Framework. A união destas duas tecnologias é muito usada no mercado de desenvolvimento de software porque ambas adquiriram uma grande aceitação em meio a comunidade, representado a junção de uma API que facilita o gerenciamento de dados relacionais em aplicações Java com um framework que reconhecidamente simplifica o desenvolvimento destas aplicações.
Spring Framework
Esse framework tem como principal objetivo simplificar o desenvolvimento de aplicações. Ele é mantido pela Spring Source e tem como proposta ser uma solução leve para a construção de aplicativos corporativos. No entanto, o Spring é modular, permitindo que você use apenas os componentes que precisar. Você pode usar o contêiner IoC com Struts na camada de visão, mas também pode usar só a integração com Hibernate, por exemplo. O Spring Framework suporta o gerenciamento de transações declarativas, acesso remoto a sua lógica através de RMI ou serviços web e várias opções para persistir os dados.
O Spring encontrou uma base de usuários muito forte ao longo dos anos. Empresas de software viram neste framework uma estrutura mais adequada para as suas necessidades (KONDA, 2011).
Projeto
Para demonstrar a integração entre as tecnologias apresentadas neste artigo, criaremos um projeto Java onde serão implementadas as quatro operações de um CRUD a partir de serviços da JPA em conjunto com o Spring Framework. A implementação destes métodos será feita utilizando a IDE Eclipse Luna e iremos usar o Maven (seção Links)para gerenciar a configuração do projeto.
O primeiro passo é a criação de um novo projeto Maven: para isso devemos acessar o menu File > New > Order > Maven Project. Após clicar em Next aparecerá a caixa de diálogo apresentada na Figura 1. A opção Create a simple Project (skip archetype selection) deve ser selecionada para que ele crie um projeto vazio.
O próximo passo é preencher os campos da forma como está sendo mostrado na Figura 2 e ao final pressione o botão Finish para criar o projeto.
Camadas do projeto
O projeto será desenvolvido em três camadas: model, persistence business. Essa divisão tem como objetivo realizar uma separação por função das classes.
A camada model será responsável pelas entidades de persistência da aplicação, a camada persistence terá as classes que realizam as ações de acesso à base de dados (persistir, atualizar, remover e buscar), enquanto a camada business será formada pelas classes de negócio, ou seja, responsáveis por realizar a regra de negócio da aplicação. Devido a isso, para melhor organizar o projeto iremos criar quatro pacotes: br.com.cazuzaneto.model, br.com.cazuzaneto.persistence, br.com.cazuzaneto.business e br.com.cazuzaneto.run. A Figura 3 apresenta a organização dos mesmos do projeto.
Configuração do projeto
Antes do processo de implementação ser iniciado é necessário que o projeto seja configurado a partir de dois arquivos XML: pom.xml e spring-context.xml.
O arquivo pom.xml, apresentado na Listagem 1, é usado para realizar as configurações que serão gerenciadas pelo Maven. Nele podemos inserir as dependências do projeto, bem como os plugins que serão instalados. No exemplo que será desenvolvido neste artigo serão usadas etedependências:
- spring-context: módulo do Spring Framework responsável por construir uma base sólida em aplicações Spring e é baseado nos módulos Core e Beans. O ponto principal deste módulo é a interface ApplicationContext, que herda BeansFactory, porém apresentando recursos adicionais a esta última. Um exemplo disso é o fato do módulo Context gerenciar também o ciclo de vida de beans de outros fornecedores, tais como algumas implementações de especificações da plataforma Java EE e o provedor Hibernate;
- spring-tx: módulo do Spring Framework responsável pela programação de transações para API diversas, tais como JTA, JDBC, Hibernate, JPA e JDO;
- spring-orm: módulo responsável por trabalhar com mapeamento objeto/relacional de uma aplicação. Possui integração com soluções como Hibernate, JPA e JDO;
- spring-aop: módulo do Spring responsável pela programação orientada a aspectos;
- hibernate-entitymanager: Implementação fornecida pelo Hibernate da especificação JPA;
- commons-dbcp2: módulo fornecido para fundação Apache (seção Links) e responsável e pela criação de Pools de conexão para bancos de dados;
- mysql-connector-java: implementação JDBC para o SGBD MySQL.
Além das dependências também foram configurados dois plugins que serão usados no projeto: maven-compiler-plugin e o maven-jar-plugin. O primeiro é responsável, dentre outras coisas, por estabelecer a versão do JDK que será usada no projeto, enquanto o segundo gerencia a execução da aplicação, inclusive definindo a classe principal a ser executada.
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>br.com.cazuzaneto</groupId>
<artifactId>spring-jpa</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>spring-jpa</name>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>4.2.4.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>4.2.4.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-orm</artifactId>
<version>4.2.4.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>4.2.4.RELEASE</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-entitymanager</artifactId>
<version>4.1.6.Final</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>4.2.4.RELEASE</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-dbcp2</artifactId>
<version>2.1.1</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.38</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.3</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<configuration>
<archive>
<manifest>
<mainClass>br.com.cazuzaneto.run.Run</mainClass>
</manifest>
</archive>
</configuration>
</plugin>
</plugins>
</build>
</project>
O segundo arquivo a ser configurado é o spring-context.xml, apresentado na Listagem 2. Ele deve ser criado dentro do pacote src/main/resources e estabelece as configurações de contexto do Spring Framework que, nesse projeto, foram feitas através da injeção de beans e da definição de tags específicas. Os beans configurados foram:
- mysqlDataSource: define a conexão com o SGBD MySQL;
- entityManagerFactory: define o EntityManager, que será responsável pelo gerenciamento das entidades da aplicação. Nesse bean também são passadas informações relacionadas à unidade de persistência e aos dados da conexão com o SGBD;
- transactionManager: define o bean responsável pelo gerenciamento das transações realizadas pelo EntityManager;
<?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: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/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">
<!-- Contexto do DispatcherServlet:
define a infraestrutura
do processamento das requisições feitas
ao Servlet (DispatcherServlet) -->
<bean id="entityManagerFactory"
class="org.springframework.orm.jpa
.LocalContainerEntityManagerFactoryBean">
<property name="persistenceUnitName" value="DEVMEDIA-UP" />
<property name="dataSource" ref="mysqlDataSource" />
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor
.HibernateJpaVendorAdapter" />
</property>
</bean>
<bean id="mysqlDataSource" class="org.apache.commons.dbcp2
.BasicDataSource">
<property name="driverClassName" value="com.mysql
.jdbc.Driver" />
<property name="url"
value="jdbc:mysql://localhost/alunodb?
createDatabaseIfNotExist=true" />
<property name="username" value="root" />
<property name="password" value="123456" />
</bean>
<bean id="transactionManager" class="org.springframework.orm
.jpa.JpaTransactionManager">
<property name="entityManagerFactory"
ref="entityManagerFactory" />
</bean>
<tx:annotation-driven />
<!-- Define o pacote base para o escaneamento das anotações de
contexto (@Component, @Repository, @Service, @Controller, etc) -->
<context:component-scan base-package="br.com.cazuzaneto" />
<context:annotation-config />
</beans>
Implementação das classes do projeto
As configurações elementares do projeto já foram realizadas e o próximo passo é dar início a implementação das classes. A primeira delas a ser desenvolvida será a AlunoEntity, apresentada na Listagem 3. Essa é, na verdade, uma entidade de persistência gerenciada pelo container JPA e responsável por conduzir os dados entre a aplicação e o SGBD, já que a JPA utiliza metadados, ou seja, anotações para realizar o mapeamento objeto/relacional. Na classe estão presentes as seguintes anotações JPA:
- Entity: anotação de classe usada para definir uma nova entidade JPA;
- Table: anotação de classe usada para definir as configurações que a classe terá quando mapeada como tabela de uma SGBD;
- Id: anotação de atributo ou método responsável por definir a chave primária da tabela;
- GeneratedValue: anotação de atributo ou método responsável por definir a estratégia de geração de chave primária. Nesse caso define que as chaves primárias serão criadas pelo próprio SGBD;
- Column: anotação de atributo ou método responsável por definir as configurações de uma coluna, tais como nome, tamanho, etc.
package br.com.cazuzaneto.model;
import java.util.Calendar;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Table;
@Entity
@Table(name = "aluno")
public class AlunoEntity {
@Id
@GeneratedValue
private Long id;
@Column(name = "nome")
private String nome;
@Column(name = "matricula")
private String matricula;
@Column(name = "data_nascimento")
private Calendar dataNascimento;
@Column(name = "sexo")
private String sexo;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getNome() {
return nome;
}
public void setNome(String nome) {
this.nome = nome;
}
public Calendar getDataNascimento() {
return dataNascimento;
}
public void setDataNascimento(Calendar dataNascimento) {
this.dataNascimento = dataNascimento;
}
public String getSexo() {
return sexo;
}
public void setSexo(String sexo) {
this.sexo = sexo;
}
}
Após a criação da classe AlunoEntity é necessário criar e configurar o arquivo persistence.xml, que deverá conter as informações da unidade de persistência que, por sua vez, é usada pela implementação da JPA. Ele deve ser criado dentro da pasta META-INF, localizada dento do pacote src/main/resources e o seu conteúdo deve ser o mesmo da Listagem 4.
<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.1"
xmlns="http://xmlns.jcp.org/xml/ns/persistence"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence
http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd">
<persistence-unit name="DEVMEDIA-UP" transaction-type="RESOURCE_LOCAL">
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<class>br.com.cazuzaneto.model.AlunoEntity</class>
<properties>
<!-- SEM as propriedades URL, login, senha e driver -->
<property name="hibernate.dialect" value="org
.hibernate.dialect.MySQL5InnoDBDialect" />
<property name="hibernate.show_sql" value="true" />
<property name="hibernate.format_sql" value="true" />
<property name="hibernate.hbm2ddl.auto" value="update" />
</properties>
</persistence-unit>
</persistence>
A segunda classe a ser implementada é a AlunoPersistence, apresentada na Listagem 5. Essa classe é responsável por realizar as ações de acesso ao banco de dados. Repare que duas anotações estão presentes: a PersistenceContext e Repository. A primeira define o atributo que receberá a injeção do EntityManager, configurado no arquivo spring-context.xml. Já a segunda define que a classe é estereotipada como uma classe de repositório e poderá ser injetada em outras classes gerenciadas pelo container do Spring.
Os métodos da classe AlunoPersistence são aqueles que fazem acesso ao banco de dados e utilizam o EntityManager.
package br.com.cazuzaneto.persistence;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import org.springframework.stereotype.Repository;
import br.com.cazuzaneto.model.AlunoEntity;
@Repository
public class AlunoPersistence {
@PersistenceContext
private EntityManager entityManager;
public void persistir(AlunoEntity entity) {
this.entityManager.persist(entity);
}
public AlunoEntity buscar(Long id) {
return this.entityManager.find(AlunoEntity.class, id);
}
public void remover(AlunoEntity alunoEntity) {
this.entityManager.remove(alunoEntity);
}
public void atualizar(AlunoEntity alunoEntity){
this.entityManager.merge(alunoEntity);
}
}
A terceira classe é a AlunoBusiness, apresentada na Listagem 6. Ela é responsável por definir a regra de negócio relacionada a aluno. Nela pode-se observar três anotações: Transactional, Service e Autowired. A anotação Transactional define que todos os métodos dessa classe que realizem transações JPA serão gerenciados pelo Spring Framework, tendo em vista a configuração realizada no arquivo spring-context.xml. A anotação Service está estereotipando a classe como sendo de serviço e define que a mesma possa ser injetada em outras classes gerenciadas pelo contêiner do Spring. Já a anotação Autowired define que o atributo anotado deve ser injetado, tendo em vista as configurações já realizadas, no caso do nosso exemplo, o atributo alunoPersistence será injetado automaticamente porque a classe AlunoPersistence foi anotada com Repository, o que permite a sua injeção em outras classes.
package br.com.cazuzaneto.business;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import br.com.cazuzaneto.model.AlunoEntity;
import br.com.cazuzaneto.persistence.AlunoPersistence;
@Transactional
@Service
public class AlunoBusiness {
@Autowired
private AlunoPersistence alunoPersistence;
public void persistirAluno(AlunoEntity entity) {
this.alunoPersistence.persistir(entity);
}
public AlunoEntity buscarAluno(Long id) {
return this.alunoPersistence.buscar(id);
}
public void removerAluno(Long id) {
AlunoEntity aux = this.buscarAluno(id);
this.alunoPersistence.remover(aux);
}
public void atualizarAluno(AlunoEntity alunoEntity) {
this.alunoPersistence.atualizar(alunoEntity);
}
}
A quarta e última classe anotada é a Run, apresentada na Listagem 7, que é responsável por iniciar a execução do projeto e onde o contexto do Spring é iniciado através da criação da classe ClassPathXmlApplicationContext. Esta recebe como parâmetro o nome do arquivo de configuração do contexto do Spring, spring-context.xml. Assim, quando o método getBean no atributo context é invocado, todas as injeções de dependência relacionadas a este bean serão realizadas.
Na classe Run é apresentado um exemplo de persistência de uma nova entidade de aluno.
package br.com.cazuzaneto.run;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import br.com.cazuzaneto.business.AlunoBusiness;
import br.com.cazuzaneto.model.AlunoEntity;
public class Run {
private static AlunoBusiness alunoBusiness;
private static ApplicationContext context;
public static void main(String[] args) {
context = new ClassPathXmlApplicationContext("spring-context.xml");
alunoBusiness = context.getBean(AlunoBusiness.class);
alunoBusiness.persistirAluno(new AlunoEntity());
}
}
Perceba que a integração de duas tecnologias muito utilizadas no mundo Java facilita a criação de um projeto com várias atividades, mas sem que para isso o desenvolvedor gaste muito tempo e código.
A aplicação do conhecimento adquirido neste artigo no seu dia a dia como desenvolvedor Java te proporcionará uma profunda abstração da complexidade presente nas tarefas de conexão a banco de dados, bem como no trabalho com os dados relacionais em aplicações orientadas objetos, isso porque a JPA oferece, além de recursos para configuração de conexões com diversos SGBDs, a possibilidade de realizar um mapeamento objeto/relacional dentro do seu próprio código fonte.
Você ainda poderá realizar tudo isso em conjunto com a infinidade de recursos que o Spring Framework te oferece, inclusive delegando a ele o papel de gerenciar as transações do JPA, além de usufruir da injeção de dependência e a integração com diversas especificações Java e tecnologias de outros fornecedores.