Esse tutorial te guiará no processo de conectar uma aplicação com multiplos MongoDBs.

O que você construirá

Você construirá uma aplicação que se conecta à multiplos MongoDBs.

Pre-req

O projeto de examplo usa Project Lombok para gerar getters, setters, contructors, etc.

Spring Boot - Conexão com MongoDB

Para criar uma instância do MongoTemplate através do Spring Boot nós só precisamos adicionar algumas propriedades específicas que o AutoConfiguration do Spring Boot se encarregará de criar tudo automaticamente.

Abaixo estão as propriedades básicas obrigatórias para criação de um MongoTemplate.

spring:
  data.mongodb:
    host: # hostname
    port: # port
    uri: #uri
    database: #db

Spring Boot tem uma classe chamada MongoProperties.java que define os campos obrigatórios com o prefixo spring.data.mongodb. (acima). A classe MongoProperties.java armazena todas as propriedades que nós escrevemos no application.yml. Então, exist outra classe chamada MongoDataAutoConfiguration.java que usa a anterior para criar um MongoTemplate.

Para conectar em dois diferentes servidores de MongoDB é necessário sobreescrever todas essas classes e comportamento.

Desligando Spring Boot AutoConfig

Para criar multiplos MongoTemplates é necessário desabilitar a auto-configuração provida pelo Spring Boot. Isso pode ser conseguido adicionando a seguinte propriedade no arquivo application.yml.

spring:
  autoconfigure:
    exclude: org.springframework.boot.autoconfigure.mongo.MongoAutoConfiguration

Configurando multiplos MongoTemplates

Primeiro crie a seguinte @ConfigurationProperties classe.

src/main/java/com/marcosbarbero/wd/multiplemongo/config/MultipleMongoProperties

import org.springframework.boot.autoconfigure.mongo.MongoProperties;
import org.springframework.boot.context.properties.ConfigurationProperties;

import lombok.Data;

@Data
@ConfigurationProperties(prefix = "mongodb")
public class MultipleMongoProperties {

    private MongoProperties primary = new MongoProperties();
    private MongoProperties secondary = new MongoProperties();
}

E então adicione as seguintes propriedades no application.yml

mongodb:
  primary:
    host: localhost
    port: 27017
    database: second
  secondary:
    host: localhost
    port: 27017
    database: second

Agora é necessário criar o MongoTemplates para ligar as configurações dadas no passo anterior.

src/main/java/com/marcosbarbero/wd/multiplemongo/config/MultipleMongoConfig

package com.marcosbarbero.wd.multiplemongo.config;

import com.mongodb.MongoClient;

import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.mongo.MongoProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.data.mongodb.MongoDbFactory;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.SimpleMongoDbFactory;

import lombok.RequiredArgsConstructor;

@Configuration
@RequiredArgsConstructor
@EnableConfigurationProperties(MultipleMongoProperties.class)
public class MultipleMongoConfig {

    private final MultipleMongoProperties mongoProperties;

    @Primary
    @Bean(name = "primaryMongoTemplate")
    public MongoTemplate primaryMongoTemplate() throws Exception {
        return new MongoTemplate(primaryFactory(this.mongoProperties.getPrimary()));
    }

    @Bean(name = "secondaryMongoTemplate")
    public MongoTemplate secondaryMongoTemplate() throws Exception {
        return new MongoTemplate(secondaryFactory(this.mongoProperties.getSecondary()));
    }

    @Bean
    @Primary
    public MongoDbFactory primaryFactory(final MongoProperties mongo) throws Exception {
        return new SimpleMongoDbFactory(new MongoClient(mongo.getHost(), mongo.getPort()),
                mongo.getDatabase());
    }

    @Bean
    public MongoDbFactory secondaryFactory(final MongoProperties mongo) throws Exception {
        return new SimpleMongoDbFactory(new MongoClient(mongo.getHost(), mongo.getPort()),
                mongo.getDatabase());
    }

}

Com a configuração acima você terá dois diferentes MongoTemplates baseados nas configurações personalizadas que criamos anteriormente.

Usando multiplos templates

No passo anterior nós criamos dois MongoTemplates, primaryMongoTemplate e secondaryMongoTemplate. Nessa sessão nós criaremos alguns modelos de dados e faremos tudo funcionar.

Criando os modelos de dados e os repositórios

Primeiro nós precisamos criar dois modelos de dados para acessar duas collections diferentes.

src/main/java/com/marcosbarbero/wd/multiplemongo/repository/primary/PrimaryModel

package com.marcosbarbero.wd.multiplemongo.repository.primary;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.mapping.Document;

@Data
@AllArgsConstructor
@NoArgsConstructor
@Document(collection = "first_mongo")
public class PrimaryModel {

	@Id
	private String id;

	private String value;

	@Override
	public String toString() {
        return "PrimaryModel{" + "id='" + id + '\'' + ", value='" + value + '\''
				+ '}';
	}
}

src/main/java/com/marcosbarbero/wd/multiplemongo/repository/secondary/SecondaryModel

package com.marcosbarbero.wd.multiplemongo.repository.secondary;

import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.mapping.Document;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@AllArgsConstructor
@NoArgsConstructor
@Document(collection = "second_mongo")
public class SecondaryModel {

    @Id
    private String id;

    private String value;

    @Override
    public String toString() {
        return "SecondaryModel{" + "id='" + id + '\'' + ", value='" + value + '\''
                + '}';
    }
}

Agora nós precisamos criar um repositório par cada modelo de dados.

src/main/java/com/marcosbarbero/wd/multiplemongo/repository/primary/PrimaryRepository

package com.marcosbarbero.wd.multiplemongo.repository.primary;

import org.springframework.data.mongodb.repository.MongoRepository;

public interface PrimaryRepository extends MongoRepository<PrimaryModel, String> {

}

src/main/java/com/marcosbarbero/wd/multiplemongo/repository/secondary/SecondaryRepository

package com.marcosbarbero.wd.multiplemongo.repository.secondary;

import org.springframework.data.mongodb.repository.MongoRepository;

public interface SecondaryRepository extends MongoRepository<SecondaryModel, String> {

}

Habilitando os repositórios Mongo

Agora nós já temos as classes para configuração das propriedades e os modelos de dados, nós precisamos configurar qual MongoTemplate será responsável para cada repository definido.

src/main/java/com/marcosbarbero/wd/multiplemongo/config/PrimaryMongoConfig

package com.marcosbarbero.wd.multiplemongo.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.data.mongodb.repository.config.EnableMongoRepositories;

@Configuration
@EnableMongoRepositories(basePackages = "com.marcosbarbero.wd.multiplemongo.repository.primary",
        mongoTemplateRef = "primaryMongoTemplate")
public class PrimaryMongoConfig {

}

src/main/java/com/marcosbarbero/wd/multiplemongo/config/SecondaryMongoConfig

package com.marcosbarbero.wd.multiplemongo.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.data.mongodb.repository.config.EnableMongoRepositories;

@Configuration
@EnableMongoRepositories(basePackages = "com.marcosbarbero.wd.multiplemongo.repository.secondary",
        mongoTemplateRef = "secondaryMongoTemplate")
public class SecondaryMongoConfig {

}

Executando

Para testar a aplicação eu adicionei o seguinte código na classe principal do projeto.

src/main/java/com/marcosbarbero/wd/multiplemongo/Application

package com.marcosbarbero.wd.multiplemongo;

import com.marcosbarbero.wd.multiplemongo.repository.primary.PrimaryModel;
import com.marcosbarbero.wd.multiplemongo.repository.primary.PrimaryRepository;
import com.marcosbarbero.wd.multiplemongo.repository.secondary.SecondaryModel;
import com.marcosbarbero.wd.multiplemongo.repository.secondary.SecondaryRepository;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

import java.util.List;

import lombok.extern.slf4j.Slf4j;

@Slf4j
@SpringBootApplication
public class Application implements CommandLineRunner {

    @Autowired
    private PrimaryRepository primaryRepository;

    @Autowired
    private SecondaryRepository secondaryRepository;

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }

    @Override
    public void run(String... args) throws Exception {
        log.info("************************************************************");
        log.info("Start printing mongo objects");
        log.info("************************************************************");
        this.primaryRepository.save(new PrimaryModel(null, "Primary database plain object"));

        this.secondaryRepository.save(new SecondaryModel(null, "Secondary database plain object"));

        List<PrimaryModel> primaries = this.primaryRepository.findAll();
        for (PrimaryModel primary : primaries) {
            log.info(primary.toString());
        }

        List<SecondaryModel> secondaries = this.secondaryRepository.findAll();

        for (SecondaryModel secondary : secondaries) {
            log.info(secondary.toString());
        }

        log.info("************************************************************");
        log.info("Ended printing mongo objects");
        log.info("************************************************************");

    }
}

Como esse projeto foi construído usando Spring Boot, para executá-lo basta apenas executar os seguintes comandos:

Build

$ ./mvnw clean package

Run

$ java -jar target/multiple-mongo-connectors-0.0.1-SNAPSHOT.jar

O processo imprimá a seguinte saída:

************************************************************
Start printing mongo objects
************************************************************
Opened connection [connectionId{localValue:3, serverValue:11}] to localhost:27017
Opened connection [connectionId{localValue:4, serverValue:12}] to localhost:27017
PrimaryModel{id='5a8834ee536b1d604345da4e', value='Primary database plain object'}
SecondaryModel{id='5a884cc8536b1da4468466a7', value='Secondary database plain object'}
************************************************************
Ended printing mongo objects
************************************************************

Para executar esse tutorial é necessário uma instancias de MongoDB rodando em localhost e na porta 27017.

Sumário

Parabéns! Você acabou de criar uma aplicação com spring-boot que conecta à múltiplas instâncias de MongoDB.

Nota de rodapé

  • O código usado para esse tutorial pode ser encontrado no github