Repositórios com vários módulos de dados Spring
1. Introdução
Às vezes, precisamos nos conectar a mais de uma tecnologia de banco de dados no mesmo aplicativo.
Neste tutorial, vamos explorar as várias opções de configuração quando se trata deusing multiple Spring Data modules in the same application.
Vamos usar uma livraria de brinquedo Spring Boot para explorar o assunto.
2. Dependências necessárias
Primeiro, precisamos adicionar nossas dependências no arquivopom.xml, para que possamos usar as ligaçõesspring-boot-starter-data-mongodbespring-boot-starter-data-cassandra Spring Boot Data:
org.springframework.boot
spring-boot-starter-data-cassandra
2.1.8.RELEASE
org.springframework.boot
spring-boot-starter-data-mongodb
2.1.8.RELEASE
3. Configuração do banco de dados
Em seguida,we need to set up the actual databases usando imagensDocker pré-construídas dehttps://hub.docker.com//cassandra[Cassandra] and https://hub.docker.com/ / mongo:
$ docker run --name mongo-db -d -p 27017:27017 mongo:latest
$ docker run --name cassandra-db -d -p 9042:9042 cassandra:latest
Esses dois comandos baixam automaticamente as imagens mais recentes do Cassandra e do MongoDB Docker e executam os contêineres reais.
Também precisamos encaminhar as portas (com a opção-p) de dentro dos contêineres no ambiente real do sistema operacional, para que nosso aplicativo possa acessar os bancos de dados.
We must create the database structure for Cassandra usando o utilitáriocqlsh. Keyspace creation cannot be done automatically by CassandraDataAutoConfiguration, então precisamos declará-lo usando a sintaxeCQL.
Então, primeiro, anexamos ao shellbash do contêiner Cassandra:
$ docker exec -it cassandra-db /bin/bash
[email protected]:/# cqlsh
Connected to Test Cluster at 127.0.0.1:9042.
[cqlsh 5.0.1 | Cassandra 3.11.4 | CQL spec 3.4.4 | Native protocol v4]
Use HELP for help.
cqlsh> CREATE KEYSPACE IF NOT exists example
WITH replication = {'class':'SimpleStrategy', 'replication_factor':1};
cqlsh> USE example;
cqlsh> CREATE TABLE bookaudit(
bookid VARCHAR,
rentalrecno VARCHAR,
loandate VARCHAR,
loaner VARCHAR,
primary key(bookid, rentalrecno)
);
Nas linhas 6 e 9, criamos o keyspace relevante e a tabela.
Poderíamos pular a criação da tabela e simplesmente contar comspring-boot-starter-data-cassandra para inicializar o esquema para nós; no entanto, como queremos explorar as configurações do framework individualmente, essa é uma etapa necessária.
Por padrão,Mongo does not impose any kind of schema validation,so there is no need to configure anything else for it. __
Finalmente, configuramos as informações relevantes sobre os bancos de dados em nossoapplication.properties:
spring.data.cassandra.username=cassandra
spring.data.cassandra.password=cassandra
spring.data.cassandra.keyspaceName=example
spring.data.cassandra.contactPoints=localhost
spring.data.cassandra.port=9042
spring.data.mongodb.host=localhost
spring.data.mongodb.port=27017
spring.data.mongodb.database=example
4. Mecanismos de detecção de armazenamento de dados
When multiple Spring Data modules are detected on the classpath, the Spring framework enters into strict repository configuration mode. Isso significa que ele usa diferentes mecanismos de detecção abaixo, para identificar qual repositório pertence a qual tecnologia de persistência.
4.1. Estendendo Interfaces de Repositório Específicas do Módulo
O primeiro mecanismo tenta determinar se um repositório estende um tipo de repositório específico do módulo Spring Data:
public interface BookAuditRepository extends CassandraRepository {
}
Para o propósito de nosso exemplo, oBookAudit.java contém alguma estrutura básica de armazenamento para rastrear usuários que emprestaram um livro:
public class BookAudit {
private String bookId;
private String rentalRecNo;
private String loaner;
private String loanDate;
// standard getters and setters
}
O mesmo se aplica à definição de repositório relacionado ao MongoDB:
public interface BookDocumentRepository extends MongoRepository {
}
Este armazena o conteúdo do livro e alguns metadados relevantes sobre ele:
public class BookDocument {
private String bookId;
private String bookName;
private String bookAuthor;
private String content;
// standard getters and setters
}
Quando o contexto do aplicativo é carregado,the framework will match each repository type using the base class it is derived from:
@Test
public void givenBookAudit_whenPersistWithBookAuditRepository_thenSuccess() {
// given
BookAudit bookAudit =
new BookAudit("lorem", "ipsum", "example", "19:30/20.08.2017");
// when
bookAuditRepository.save(bookAudit);
// then
List result = bookAuditRepository.findAll();
assertThat(result.isEmpty(), is(false));
assertThat(result.contains(bookAudit), is(true));
}
Você pode notar que nossas classes de domínio são objetos Java simples. Nesta situação particular, o esquema do banco de dados Cassandra deve ser criado externamente comCQL, como fizemos na seção 3.
4.2. Usando anotações específicas do módulo nos objetos de domínio
A segunda estratégiadetermines the persistence technology based on module-specific annotations on the domain objects.
Vamos estender umCrudRepostitory genérico e contar agora com as anotações de objetos gerenciados para detecção:
public interface BookAuditCrudRepository extends CrudRepository {
}
public interface BookDocumentCrudRepository extends CrudRepository {
}
OBookAudit.java agora fica anotado com o@Table específico do Cassandra e requer uma chave primária composta:
@Table
public class BookAudit {
@PrimaryKeyColumn(type = PrimaryKeyType.PARTITIONED)
private String bookId;
@PrimaryKeyColumn
private String rentalRecNo;
private String loaner;
private String loanDate;
// standard getters and setters
}
Escolhemos a combinação debookId erentalRecNo como nosso critério exclusivo, pois nosso aplicativo simplesmente registra um novo registro de aluguel cada vez que alguém empresta um livro.
ParaBookDocument.java, usamos a anotação@Document, que é específica do MongoDB:
@Document
public class BookDocument {
private String bookId;
private String bookName;
private String bookAuthor;
private String content;
// standard getters and setters
}
O acionamento de um salvamento deBookDocument comCrudRepository ainda é bem-sucedido, mas o tipo retornado na linha 11 agora é umIterable em vez de umList:
@Test
public void givenBookAudit_whenPersistWithBookDocumentCrudRepository_thenSuccess() {
// given
BookDocument bookDocument =
new BookDocument("lorem", "Foundation", "Isaac Asimov", "Once upon a time ...");
// when
bookDocumentCrudRepository.save(bookDocument);
// then
Iterable resultIterable = bookDocumentCrudRepository.findAll();
List result = StreamSupport.stream(resultIterable.spliterator(), false)
.collect(Collectors.toList());
assertThat(result.isEmpty(), is(false));
assertThat(result.contains(bookDocument), is(true));
}
4.3. Usando o escopo baseado em pacote
Finalmente,we can specify the base packages where our repositories are defined, usando as anotações@EnableCassandraRepositoriese@EnableMongoRepositories:
@EnableCassandraRepositories(basePackages="com.example.multipledatamodules.cassandra")
@EnableMongoRepositories(basePackages="com.example.multipledatamodules.mongo")
public class SpringDataMultipleModules {
public static void main(String[] args) {
SpringApplication.run(SpringDataMultipleModules.class, args);
}
}
Como podemos ver nas linhas 1 e 2,this configuration mode assumes we use different packages for the Cassandra and MongoDB repositories.
5. Conclusão
Neste tutorial, configuramos um aplicativo Spring Boot simples para usar dois módulos Spring Data diferentes de três maneiras.
Como um primeiro exemplo, estendemosCassandraRepositoryeMongoRepositorye usamos classes simples para os objetos de domínio.
Em nossa segunda abordagem, estendemos a interfaceCrudRepository genérica e contamos com as anotações específicas do módulo, como@Tablee@Document em nossos objetos gerenciados.
No final, usamos a detecção baseada em pacote quando configuramos o aplicativo com a ajuda de@EnableCassandraRepositoriese@EnableMongoRepositories.
Como sempre, o código completo está disponívelover on GitHub.