使用 mongodb-reactive 的反应式 Spring boot 应用程序中的多租户

2024-06-26

我们如何使用 Mongodb-reactive 存储库在 spring webflux 中创建多租户应用程序?

我在网上找不到任何有关反应式应用程序的完整资源。所有可用资源均适用于非反应式应用程序。

UPDATE:

在非响应式应用程序中,我们过去常常将上下文数据存储在 ThreadLocal 中,但这不能在响应式应用程序中完成,因为存在线程切换。有一种方法可以将上下文信息存储在 WebFilter 内的 Reactor Context 中,但我不知道如何获取该数据ReactiveMongoDatabaseFactory class.

Thanks.


我能够使用 mangodb 在 Spring Reactive 应用程序中实现多租户。负责实现的主要类有:自定义的MongoDbFactory类、用于捕获租户信息的WebFilter类(而不是Servlet Filter)和用于存储租户信息的ThreadLocal类。流程非常简单:

  1. 从 WebFilter 中的请求中捕获租户相关信息并将其设置在 ThreadLocal 中。在这里,我使用标头发送租户信息:X-Tenant
  2. 实现自定义 MondoDbFactory 类并覆盖getMongoDatabase()方法根据 ThreadLocal 类中可用的当前租户返回数据库。

源代码是:

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());
    }
}

多租户MongoDbFactory.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;
    }
}

UPDATE:

在反应流中,我们无法再将上下文信息存储在 ThreadLocal 中,因为请求不绑定到单个线程,因此,这不是正确的解决方案。

然而,上下文信息可以像这样存储在WebFilter中的reactor Context中。chain.filter(exchange).subscriberContext(context -> context.put("tenant", tenant));。问题是如何获取这些上下文信息ReactiveMongoDatabaseFactory实现类。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

使用 mongodb-reactive 的反应式 Spring boot 应用程序中的多租户 的相关文章

  • MongoDB 的优点和缺点? [关闭]

    就目前情况而言 这个问题不太适合我们的问答形式 我们希望答案得到事实 参考资料或专业知识的支持 但这个问题可能会引发辩论 争论 民意调查或扩展讨论 如果您觉得这个问题可以改进并可能重新开放 访问帮助中心 help reopen questi
  • 如何将后端计时器与移动应用程序同步

    我正在开发一个选择用户并有 15 秒时间的应用程序 该用户响应的计时器 用户应用程序每 5 秒查询一次数据库 以查看是否选择了该用户 如果是这样 移动应用程序将开始 15 秒 定时器 问题是计时器永远不会匹配 因为用户应用程序可以位于与后端
  • MEAN 堆栈文件上传

    我最近开始使用 MEAN Stack 进行编程 目前正在实现某种社交网络 一直使用 MEAN io 框架来做到这一点 我现在的主要问题是让文件上传正常工作 因为我想做的是将文件从表单接收到 AngularJS 控制器中 并将其与更多信息一起
  • MongoDB list集合过滤器

    我正在使用 Node js 我正在尝试过滤必须排除集合 出口 的集合并检索所有其他集合 但我似乎无法弄清楚语法 我试过了 db listCollections filter outlets toArray err docs 有什么建议么 您
  • 获取背景图片url值

    我正在尝试获取背景图像 url 的值 url 直接在元素标签中使用 style 属性内联设置 如下所示 a style background image none a 我尝试做 var url this css background ima
  • 如何在猫鼬中使用.slice

    我在我的应用程序中得到了这个 Score find match in ids sort score sort descending slice skip limit exec function err scores if err score
  • Symfony2 的 mongoDB 返回一个可记录游标而不是我的实体

    我目前使用 DoctrineMongoDbBundle 向我的 mongodb 数据库发出请求 这是我的控制器中的调用 dm this gt get doctrine odm mongodb document manager entitie
  • 在mongo聚合中选择* group by

    我正在尝试做一些我认为很简单的事情 假设我在 mongo 中有一系列具有公共键和可变数量属性的记录 我想选择记录中的所有属性并按名称分组 例如 Name George x 5 y 3 Name George z 9 Name Rob x 1
  • 如何在 mongodb 中对数组进行 AND 查询?

    我有一个带有标签的数组 它是文档的一部分 例如 红 绿 蓝 白 黑 现在我想找到所有有红色和蓝色的文档 使用 all 条件查找同时匹配 红色 和 蓝色 条件的记录 db my collection find tags all red blu
  • Mongodb集合对象总小时数集合

    mongodb 收集数据 提前感谢 id ObjectId 5f7b3d78e95af70e17efd6d6 employeeId 2707 employeeName HrJosh status Present date 2020 10 1
  • Mongoose 中的分组(依据)?

    我已经在 shell 中构建了我想要的查询 但在 Mongoose 中编写它时遇到了问题 db commentstreams group key page id true reduce function obj prev prev num
  • Mongoose 在结果的 _id 字段中返回“new ObjectId”

    当我尝试查询时 结果包含 id其中包含 new ObjectId 的字段 如何避免这种 new ObjectId 并仅将哈希值包含为字符串 由于此问题 将数据作为 JSON 响应发送回失败 下面是一个基本的demo 我的查询代码 book
  • 使用 mongodb-reactive 的反应式 Spring boot 应用程序中的多租户

    我们如何使用 Mongodb reactive 存储库在 spring webflux 中创建多租户应用程序 我在网上找不到任何有关反应式应用程序的完整资源 所有可用资源均适用于非反应式应用程序 UPDATE 在非响应式应用程序中 我们过去
  • Mongoose 5.x 不允许传递大量运算符

    聚合查询返回错误 Mongoose 5 x 不允许将操作符传递给Model aggregate 代替Model aggregate match skip do Model aggregate match skip 我正在使用 mongoos
  • node-mongodb-native MongoClient 意外关闭连接

    我一直在 mongodb 中搜索大量意外关闭的连接 但只能找到希望关闭连接的人提出的问题 我正在使用 node mongodb native 连接到数据库 但我不断收到看似随机的 错误 连接已关闭 消息 如果我手动重试请求 浏览器刷新 则请
  • mongoose 查询:通过 id 在数组中查找对象

    我怎样才能在此 Schema 中通过 id 找到图像 我有用户的 id 和我正在寻找的图像的 id 执行此操作的最佳方法是什么 在这种情况下 所有图像是否具有不同的 id 或者它们是否可以具有相同的 id 因为它们不属于同一用户 我的架构如
  • Spring boot 2.0.5.RELEASE和mongo 4.0连接问题

    我正在关注使用 MongoDB 访问数据教程春季网站 https spring io guides gs accessing data mongodb 我将 Mongo DB 服务器版本 4 安装为服务当我使用客户端连接到它时 它的身份验证
  • Meteor `Deps.autorun` 与 `Collection.observe`

    使用之间有什么优点 缺点Deps autorun or Collection observe使第三方小部件与反应式小部件保持同步Meteor Collection 例如 我使用 jsTree 直观地显示我存储在 MongoDB 中的目录树
  • Mongoose:populate() / DBref 或数据重复?

    我有两个收藏 Users Uploads 每次上传都有一个User与之相关 当我需要知道他们的详细信息Upload被查看 最佳做法是在上传记录中复制此数据 还是使用填充 http mongoosejs com docs populate h
  • 使用 Flask 和 MongoEngine 跟踪 Tumblelog 应用程序时出错

    我正在关注 tumbleblog 应用程序here http docs mongodb org ecosystem tutorial write a tumblelog application with flask mongoengine

随机推荐

  • 从 blob 反序列化 java 对象

    首先 我很抱歉 我要问一些愚蠢的问题 我根本不懂java 也不知道我们是否可以问这样的问题 如果没有 删除我的主题 oracle中有一个存储blob的表 它是二进制的 我能够解码它 输出看起来像这样 sr com epam insure c
  • 我必须实现 Applicative 和 Functor 来实现 Monad

    我正在尝试实现一个 Monad 实例 作为一个更简单的示例 假设如下 data Maybee a Notheeng Juust a instance Monad Maybee where return x Juust x Notheeng
  • 如何在 C 中将 int 和数组保存在共享内存中?

    我正在尝试编写一个程序 让子进程在 Linux 上相互通信 这些进程都是从同一个程序创建的 因此它们共享代码 我需要它们能够访问两个整数变量以及一个整数数组 我不知道共享内存是如何工作的 我搜索过的每一个资源除了让我困惑之外什么也没做 任何
  • Spark中DataFrame、Dataset、RDD的区别

    我只是想知道有什么区别RDD and DataFrame Spark 2 0 0 DataFrame 只是一个类型别名Dataset Row 在阿帕奇火花 你能将其中一种转换为另一种吗 首先是DataFrame是从SchemaRDD 是的
  • java 未知深度的嵌套哈希图

    我有一个要求 我需要有一个嵌套的哈希图 但深度将在运行时决定 例如 如果在运行时 用户说 3 那么我的哈希图应该是这样的 HashMap
  • 在无形状中,有两个列表,其中一个包含另一个的类型类

    在无形中 我正在尝试编写一个需要两个 HList 的函数l1 and l2任意长度 具有以下属性 的长度l1 and l2是相同的 l2包含的确切类型l1 包装在常量外部类型构造函数中 So if l1 was 1 1 2 hello HN
  • 对数据绑定组合框进行排序的最佳方法是什么?

    我对此做了一些研究 似乎对数据绑定组合框进行排序的唯一方法是对数据源本身进行排序 在本例中为数据集中的数据表 如果是这种情况 那么问题就变成对数据表进行排序的最佳方法是什么 组合框绑定在设计器中设置初始化使用 myCombo DataSou
  • Python:如何即时生成代码?

    我遇到了一个问题 我必须动态生成程序然后执行它 我们怎样才能做到这一点 您可以使用 eval 函数从字符串执行代码 一个例子是 import math test r dir math eval test Output doc name pa
  • 如何在 Sublime Text 3 中设置语法的默认文件扩展名?

    我不是在询问将语法与文件扩展名相关联 而是在询问将文件扩展名与语法相关联 也就是说 在创建新文件后设置保存文件对话框中建议的文件扩展名 然后设置语法 然后单击 保存 您可以在保存对话框中更改扩展名 但最好不要每次都这样做 用于保存纯文本文件
  • 如何找到权重为 1、0、-1 且成本精确为 0 的多维路径

    我得到了一个有向图 其中有 n 个节点和边 向量的权重 每个向量的长度为 m 为数字 1 0 1 我想找到从一个节点到另一个节点 我们可以多次访问节点 的任何路径 或者说这样的路径不存在 使其权重之和等于仅由零组成的向量 我正在考虑暴力回溯
  • 关于调试打印样式表的建议?

    我最近一直在为一个网站制作打印样式表 我意识到我不知道如何有效地调整它 在屏幕布局上工作时有一个重新加载周期是一回事 更改代码 命令选项卡 reload 但是当您尝试打印时 整个过程会变得更加困难 更改代码 命令选项卡 reload pri
  • Postgres:跨行连接 JSONB 值?

    我正在掌握 Postgres gt 9 5 中的 JSONB 功能 并且很喜欢它 但遇到了障碍 我读过有关连接 JSON 字段的功能 所以 a 1 b 2 创造 a 1 b 2 但我想在多行的同一字段中执行此操作 例如 select row
  • TPL架构问题

    我目前正在开展一个项目 我们面临并行处理项目的挑战 到目前为止没什么大不了的 现在来说说问题 我们有一个 ID 列表 我们定期 每 2 秒 为每个 ID 调用一个 StoredProcedure 需要单独检查每个项目的 2 秒 因为它们是在
  • symfony2 选择单选框的默认值

    我的项目是使用 Silex 和 Symfony 组件 即表单组件 编写的 我尝试创建一组从类中构建的单选按钮 并且我想预先选择其中一个单选按钮 我创建这样的表格 form app form factory gt createBuilder
  • 选项卡集 $rootScope 范围未更新

    我的屏幕结构如下 UserExperienceScreen
  • ValueError:张量必须与张量来自同一个图

    我正在尝试在张量流中构建图表 但遇到以下错误 ValueError 张量 transformation 0 输出 输出 0 形状 dtype float32 必须来自同一个图表 张量 变量 总输出 0 形状 dtype float32 re
  • 大十进制减法

    我想减去2double值 我尝试了以下代码 double val1 2 0 double val2 1 10 System out println val1 val2 我得到的输出为 0 8999999999999999 为了获得输出0 9
  • 如何防止Rails“复数”列名?

    我正在使用 dwilkie 的外国人 http github com dwilkie foreignerRails 插件 我有一个表创建语句 如下所示 create table agents games force gt true id g
  • 如何在 Tomcat 6 中合理配置安全策略

    我使用的是为 Ubuntu Karmic 打包的 Tomcat 6 0 24 Ubuntu 的 Tomcat 软件包的默认安全策略相当严格 但看起来很简单 在 var lib tomcat6 conf policy d 有多种建立默认策略的
  • 使用 mongodb-reactive 的反应式 Spring boot 应用程序中的多租户

    我们如何使用 Mongodb reactive 存储库在 spring webflux 中创建多租户应用程序 我在网上找不到任何有关反应式应用程序的完整资源 所有可用资源均适用于非反应式应用程序 UPDATE 在非响应式应用程序中 我们过去