MongoDB
 sql >> Cơ Sở Dữ Liệu >  >> NoSQL >> MongoDB

Multi-Tenancy trong ứng dụng khởi động Reactive Spring sử dụng mongodb-reacttive

Tôi đã có thể Triển khai Đa thuê nhà trong ứng dụng Spring Reactive bằng cách sử dụng mangodb. Các lớp chính chịu trách nhiệm nhận ra là:lớp MongoDbFactory tùy chỉnh, lớp WebFilter (thay vì Bộ lọc Servlet) để thu thập thông tin về người thuê và lớp ThreadLocal để lưu trữ thông tin về người thuê. Quy trình rất đơn giản:

  1. Thu thập thông tin liên quan đến Người thuê từ yêu cầu trong WebFilter và đặt nó trong ThreadLocal. Ở đây, tôi đang gửi thông tin về Người thuê sử dụng tiêu đề:X-Tenant
  2. Triển khai lớp MondoDbFactory tùy chỉnh và ghi đè getMongoDatabase() phương thức trả về cơ sở dữ liệu dựa trên đối tượng thuê hiện tại có sẵn trong lớp ThreadLocal.

Mã nguồn là:

CurrentTenantHolder.java

package com.jazasoft.demo;

public class CurrentTenantHolder {
    private static final ThreadLocal<String> currentTenant = new InheritableThreadLocal<>();

    public static String get() {
        return currentTenant.get();
    }

    public static void set(String tenant) {
        currentTenant.set(tenant);
    }

    public static String remove() {
        synchronized (currentTenant) {
            String tenant = currentTenant.get();
            currentTenant.remove();
            return tenant;
        }
    }
}

TenantContextWebFilter.java

package com.example.demo;

import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.server.WebFilter;
import org.springframework.web.server.WebFilterChain;
import reactor.core.publisher.Mono;

@Component
public class TenantContextWebFilter implements WebFilter {

    public static final String TENANT_HTTP_HEADER = "X-Tenant";

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) {
        ServerHttpRequest request = exchange.getRequest();
        if (request.getHeaders().containsKey(TENANT_HTTP_HEADER)) {
            String tenant = request.getHeaders().getFirst(TENANT_HTTP_HEADER);
            CurrentTenantHolder.set(tenant);
        }
        return chain.filter(exchange).doOnSuccessOrError((Void v, Throwable throwable) -> CurrentTenantHolder.remove());
    }
}

MultiTenantMongoDbFactory.java

package com.example.demo;

import com.mongodb.reactivestreams.client.MongoClient;
import com.mongodb.reactivestreams.client.MongoDatabase;
import org.springframework.dao.DataAccessException;
import org.springframework.data.mongodb.core.SimpleReactiveMongoDatabaseFactory;


public class MultiTenantMongoDbFactory extends SimpleReactiveMongoDatabaseFactory {
    private final String defaultDatabase;

    public MultiTenantMongoDbFactory(MongoClient mongoClient, String databaseName) {
        super(mongoClient, databaseName);
        this.defaultDatabase = databaseName;
    }


    @Override
    public MongoDatabase getMongoDatabase() throws DataAccessException {
        final String tlName = CurrentTenantHolder.get();
        final String dbToUse = (tlName != null ? tlName : this.defaultDatabase);
        return super.getMongoDatabase(dbToUse);
    }
}

MongoDbConfig.java

package com.example.demo;

import com.mongodb.reactivestreams.client.MongoClient;
import com.mongodb.reactivestreams.client.MongoClients;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.mongodb.core.ReactiveMongoClientFactoryBean;
import org.springframework.data.mongodb.core.ReactiveMongoTemplate;

@Configuration
public class MongoDbConfig {

    @Bean
    public ReactiveMongoTemplate reactiveMongoTemplate(MultiTenantMongoDbFactory multiTenantMongoDbFactory) {
        return new ReactiveMongoTemplate(multiTenantMongoDbFactory);
    }

    @Bean
    public MultiTenantMongoDbFactory multiTenantMangoDbFactory(MongoClient mongoClient) {
        return new MultiTenantMongoDbFactory(mongoClient, "test1");
    }

    @Bean
    public ReactiveMongoClientFactoryBean mongoClient() {
        ReactiveMongoClientFactoryBean clientFactory = new ReactiveMongoClientFactoryBean();
        clientFactory.setHost("localhost");
        return clientFactory;
    }
}

CẬP NHẬT:

Trong luồng phản ứng, chúng tôi không thể lưu trữ thông tin ngữ cảnh trong ThreadLocal nữa vì yêu cầu không được ràng buộc với một luồng duy nhất, Vì vậy, Đây không phải là giải pháp chính xác.

Tuy nhiên, thông tin ngữ cảnh có thể được lưu trữ Context lò phản ứng trong WebFilter như thế này. chain.filter(exchange).subscriberContext(context -> context.put("tenant", tenant)); . Vấn đề là làm thế nào để nắm giữ thông tin ngữ cảnh này trong ReactiveMongoDatabaseFactory lớp triển khai.



  1. Redis
  2.   
  3. MongoDB
  4.   
  5. Memcached
  6.   
  7. HBase
  8.   
  9. CouchDB
  1. MongoDB thực hiện lập chỉ mục nội bộ?

  2. Kích thước mảng tổng hợp Mongo DB lớn hơn khớp

  3. MongoDb Khác biệt với trình điều khiển C # truy vấn

  4. Có giải pháp nào để cho phép sử dụng regex trong đường ống tổng hợp Mongodb không

  5. Plugin thay thế cho plugin river-mongodb đàn hồi, được hỗ trợ bởiasticsearch 2.2.0 là gì?