O Spring é um framework open source cujo o objetivo sempre foi facilitar a vida do desenvolvedor Java, começou com os recursos para injeção de dependência e hoje atua em diversas atividades triviais para um programador. Entre elas podemos citar a parte social com o Spring social no twitter, facebook, segurança com o Spring security além do já inversão de controle e inversão de dependência. O foco desse pequeno post é falar sobre o Spring Data e seu trabalho com o banco não relacional Cassandra.
O Spring-data é um pequeno módulo ou plugin do Spring e tem como objetivo auxiliar nos processos triviais de persistência criando uma camada entre a base onde se encontra as informações e o seu código java. Dessa maneira é possível, efetuar ações na base, usando como estrutura para as informações, o POJO (simples e velho objetos em java). Dentro do Spring Data já existem diversos tipo de base de informações.
- Bancos Relacionais com JPA e JDBC
- BigData com Apache Hadoop
- Data-Grid com GermFire
- HTTP com Rest
- NOSQL com MongoDB, Neo4J, Redis e Hbase
Uma das grandes vantagem do Spring Data é ser filho do Spring. Ele não precisa de um servidor Java EE, ou seja, ele pode rodar em um simples contêiner como o tomcat ou mesmo rodar sem o auxílio do servidor. Sua injeção funciona com auxílio de um arquivo xml, mas não necessariamente toda configuração é feita por lá, existem várias anotações que podem ajudar o desenvolvedor, no entanto, cabe apenas ao mesmo saber em qual momento é mais adequado usar cada um deles.
Com esse foco o Spring Data Cassandra tem o foco de criar uma camada de alto nível para o nosql Cassandra, assim é possível com estruturas de POJOs estabelecer uma conexão no banco e realizar as operações CRUD, tudo isso sem abrir mão da estrutura de dados já conhecida pelo desenvolvedor Java. O Spring Data Cassandra ainda não foi fechada, mas o Easy-Cassandra já possui integração com Spring, agora é possível utilizá-lo com a injeção de dependências do framework Java mais famoso do mundo.
A aplicação será realmente bastante simples seu objetivo será apenas criar uma informação e armazenar no banco, em seguida recuperar pelo id. O primeiro passo será a criação da entidade pessoa, ela terá os campos id, nome e ano, conforme mostra a tabela número1.
@Entity(name = "person")
public class Person implements Serializable {
@Id
private UUID id;
@Index
@Column(name = "name")
private String name;
@Column(name = "born")
private Integer year;
//getter and setter
}
Como pode ser visto os campos são anotados via JPA 2.0, o segundo passo é a criação do xml, é nele que conterá as configurações do banco de dados (host, porta, keyspace padrão, etc.). O próximo passo é a configuração e criação da fábrica de conexões para o Cassandra dentro do spring, isso é, o host, porta e o keyspace padrão, e as classes que serão mapeadas como mostra no arquivo xml abaixo.
<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"
xsi:schemaLocation="http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
<context:component-scan base-package="org.javabahia.cassandra.spring" />
<bean id="cassandraFactory"
class="org.easycassandra.persistence.cassandra.spring.CassandraFactoryAnnotation">
<constructor-arg name="host" value="localhost" />
<constructor-arg name="keySpace" value="spring" />
<property name="annotatedClasses">
<list>
<value>org.javabahia.cassandra.spring.entity.Person</value>
</list>
</property>
</bean>
<bean id="cassandraTemplate"
class="org.easycassandra.persistence.cassandra.spring.SimpleCassandraTemplateImpl" >
<constructor-arg name="factory" ref="cassandraFactory" />
</bean>
</beans>
Com a fábrica de conexões do cassandra é possível retornar uma sessão, a via de comunicação do Cassandra com a aplicação Java, além disso será criado o CassandraTemplate, uma api de alto nível que consegue realizar a comunicação Cassandra sua aplicação a partir de um simples POJO, desse modo é possível realizar a operação CRUD de uma maneira bastante simples, o código abaixo mostra a interface do Cassandra template.
public interface CassandraTemplate{
<T> T save(T entity);
<T> Iterable<T> save(Iterable<T> entities);
<T> void delete(T entity);
<T> void delete(Iterable<T> entities);
<K> void delete(K key, Class<?> entity);
<K,T> void delete(Iterable<K> keys, Class<T> entity);
<T> void deleteAll(Class<T> entity);
<T> T update(T entity);
<T> Iterable<T> update(Iterable<T> entities);
<T,K> T findOne(K key, Class<T> entity);
<T,K> List<T> findAll(Iterable<K> keys, Class<T> entity);
<T> List<T> findAll(Class<T> entity);
<T,I> List<T> findByIndex(String columnName,I index,Class<T> entity);
<K,T>boolean exist(K key, Class<T> entity);
void executeUpdate(String query);
Além do CassandraTemplate existe o CassandraRepository, essa classe abstrata implementa o CrudRepository do SpringData, com ela é necessário apenas implementar o método que retornará o CassandraTemplate, conforme mostra a tabela abaixo.
@Repository("personRepository")
public class PersonRepository extends CassandraRepository<Person, UUID>{
@Autowired
private CassandraTemplate cassandraTemplate;
@Override
protected CassandraTemplate getCassandraTemplate() {
return cassandraTemplate;
}
}
Como o CassandraReporitory implementa a classe base de operações do Spring todas as suas operações estarão disponíveis para serem utilizadas com o Cassandra.
public interface CrudRepository<T, ID extends Serializable> extends Repository<T, ID> {
<S extends T> S save(S entity);
<S extends T> Iterable<S> save(Iterable<S> entities);
T findOne(ID id);
boolean exists(ID id);
Iterable<T> findAll();
Iterable<T> findAll(Iterable<ID> ids);
long count();
void delete(ID id);
void delete(T entity);
void delete(Iterable<? extends T> entities);
void deleteAll();
}
Realizado as configurações o próximo passo é executar o projeto como mostra o código a seguir:
public class App
{
public static void main( String[] args )
{
@SuppressWarnings("resource")
ApplicationContext ctx = new GenericXmlApplicationContext("SpringConfig.xml");
PersonRepository personService=ctx.getBean(PersonRepository.class);
UUID uuid=UUID.randomUUID();
Person person=new Person();
person.setId(uuid);
person.setName("Otávio Santana");
person.setYear(25);
personService.save(person);
Person otavio=personService.findOne(uuid);
System.out.println(otavio.getName());
}
}
Com isso foi demonstrado o conceito do Spring Data e o seu funcionamento com o Cassandra utilizando o Easy-Cassandra, o intuito criar uma interface padrão para que todos os modelos de persistência a utilizem dentro do Spring é um grande e importante passo para utilizar uma nova base ou modelo de dados não haja impacto dentro do Spring, mas é muito importante salientar que mesmo que vários bancos utilizem essa interface é importante considerar uma nova modelagem, já que diferente dos bancos relacionais, a mudança de um banco NOSQL pode significar a mudança estrutura de armazenamento.