вторник, 19 декабря 2017 г.

Spring Boot и MongoDB работа с несколькими базами

Настройка контекста Spring Boot для работы с двумя базами MongoDB не очевидна и требует времени на реализацию.

Цель:


  • Обеспечить возможность работы приложения с двумя базами одновременно
  • Работа должна производиться через MongoRepository
  • Для запуска Unit тестов должен использоваться Embedded MongoDB

1. Для старта используется класс приложения с аннотациями @EnableAutoConfiguration и @ComponentScan


    2. Конфигурация для основной базы данных:

    @Configuration
    @EnableMongoRepositories(value = "ru.xxx.repository", repositoryFactoryBeanClass = MongoCrudRepositoryFactoryBean.class, mongoTemplateRef = "mongoTemplate",
            excludeFilters = @ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, classes = CustomerActivityRepository.class))
    public class MainDatabaseConfiguration extends AbstractMongoConfiguration {
    
        private Mongo mongo;
    
        private final MongoProperties mongoProperties;
    
        private final MongoClientOptions options;
    
        private final Environment environment;
    
        public MainDatabaseConfiguration(MongoProperties mongoProperties, ObjectProvider<MongoClientOptions> options, Environment environment) {
            this.mongoProperties = mongoProperties;
            this.options = options.getIfAvailable();
            this.environment = environment;
        }
    
        @Override
        protected String getDatabaseName() {
            return mongoProperties.getDatabase();
        }
    
        @Override
        @Bean(name = "mongo")
        public Mongo mongo() throws UnknownHostException {
            this.mongo = this.mongoProperties.createMongoClient(this.options, this.environment);
            return this.mongo;
        }
    
        @Override
        @Bean(name = "mongoDbFactory")
        public MongoDbFactory mongoDbFactory() throws Exception {
            return super.mongoDbFactory();
        }
    
        @Override
        @Bean(name = "mongoTemplate")
        public MongoTemplate mongoTemplate() throws Exception {
            return super.mongoTemplate();
        }
    
        @PreDestroy
        public void close() {
            if (this.mongo != null) {
                this.mongo.close();
            }
        }
    
    }
    
    
    Важные детали:
    • mongoTemplateRef - шаблон для работы с основной базой. 
    • excludeFilters - фильтр, исключающий репозитории для работы со второй базой. 
    • Для получения настроек БД используется org.springframework.boot.autoconfigure.mongo.MongoProperties

    2. Конфигурация для дополнительной базы данных:

    @Configuration
    @EnableMongoRepositories(value = "ru.xxx.repository", repositoryFactoryBeanClass = MongoCrudRepositoryFactoryBean.class, mongoTemplateRef = "mongoTemplateActivity",
            includeFilters = @ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, classes = CustomerActivityRepository.class))
    @EnableConfigurationProperties(ActivityMongoProperties.class)
    public class ActivityDatabaseConfiguration extends AbstractMongoConfiguration {
    
        private Mongo mongo;
    
        private ActivityMongoProperties mongoProperties;
    
        private final MongoClientOptions options;
    
        private final Environment environment;
    
        public ActivityDatabaseConfiguration(ActivityMongoProperties properties, ObjectProvider<MongoClientOptions> options, Environment environment) {
            this.mongoProperties = properties;
            this.options = options.getIfAvailable();
            this.environment = environment;
        }
    
        @Override
        protected String getDatabaseName() {
            return mongoProperties.getDatabase();
        }
    
        @Override
        @Bean(name = "mongoActivity")
        public Mongo mongo() throws UnknownHostException {
            this.mongo = this.mongoProperties.createMongoClient(this.options, this.environment);
            return this.mongo;
        }
    
        @Override
        @Bean(name = "mongoDbFactoryActivity")
        public MongoDbFactory mongoDbFactory() throws Exception {
            return super.mongoDbFactory();
        }
    
        @Override
        @Bean(name = "mongoTemplateActivity")
        public MongoTemplate mongoTemplate() throws Exception {
            return super.mongoTemplate();
        }
    
        @PreDestroy
        public void close() {
            if (this.mongo != null) {
                this.mongo.close();
            }
        }
    }
    
    Важные детали:
    • mongoTemplateRef - шаблон для работы с дополнительной базой. 
    • includeFilters - фильтр, включающий репозитории для работы со второй базой. 
    • Для получения настроек БД используется org.springframework.boot.autoconfigure.mongo.ActivityMongoProperties. Класс ActivityMongoProperties полностью дублирует класс org.springframework.boot.autoconfigure.mongo.MongoProperties за исключением @ConfigurationProperties(prefix = "spring.data.mongodb_activity"). При наследование появляется проблема с инжекцией MongoProperties в компоненты MongoDataAutoConfiguration и др.

    3. Конфигурация для embedded режима:

    @Configuration
    @EnableConfigurationProperties({ MongoProperties.class, EmbeddedMongoProperties.class })
    @AutoConfigureBefore(MainDatabaseConfiguration.class)
    @ConditionalOnClass({ Mongo.class, MongodStarter.class })
    public class EmbeddedMainDatabaseConfiguration extends EmbeddedMongoAutoConfiguration {
    
        public EmbeddedMainDatabaseConfiguration(MongoProperties properties,
                                              EmbeddedMongoProperties embeddedProperties, ApplicationContext context,
                                              IRuntimeConfig runtimeConfig) {
            super(properties, embeddedProperties, context, runtimeConfig);
        }
    
    }
    
    Важные детали:
    • EmbeddedMainDatabaseConfiguration - находится в src/test 

    4. Итоговый файл настроек:

    spring:
        aop:
            proxy-target-class: true
        data:
            mongodb:
                host: localhost
                port: 27017
                database: main_db
            mongodb_activity:
                host: localhost
                port: 27017
                database: activity_db