Activiti中具有单独数据库模式的多租户

我们过去听到的一项功能请求是以多租户方式运行Activiti引擎,使租户的数据与其他租户的数据隔离。 当然,在某些云/ SaaS环境中,这是必须的。

几个月前,波恩大学的学生拉斐尔·吉伦(Raphael Gielen)与我接触,他正在撰写有关Activiti中多租户的硕士论文。 几周前,我们在一个共同工作的咖啡馆聚会,反弹想法,并为租户一起破解了具有数据库模式隔离的第一个原型。 很有趣 :-)。

无论如何,我们一直在完善和完善该代码,并将其提交给Activiti代码库。 让我们在下面的前两个部分中了解使用Activiti进行多租户的现有方法。 在第三部分中,我们将深入研究新的多租户多模式功能,其中包含一些实际工作的代码示例!

共享数据库多租户

Activiti已经有多租户功能了一段时间(自版本5.15起)。 所采用的方法是共享数据库 :拥有一个(或多个)Activiti引擎,并且它们都进入同一个数据库。 数据库表中的每个条目都有一个租户标识符 ,最好将其理解为该数据的一种标记。 然后,Activiti引擎和API会读取并使用该租户标识符在租户的上下文中执行其各种操作。

例如,如下图所示,两个不同的租户可以具有使用相同密钥的流程定义。 引擎和API确保没有数据混合。

截图-2015-10-06-12.57.00

这种方法的好处是部署简单,因为与设置“常规” Activiti引擎没有区别。 缺点是您必须记住使用正确的API调用(即那些考虑了租户标识符的调用)。 而且,它与任何具有共享资源的系统都存在相同的问题:租户之间总是存在对资源的竞争。 在大多数用例中,这很好,但是有些用例不能以这种方式完成,例如为某些租户提供更多或更少的系统资源。

多引擎多租户

自Activiti的第一个版本以来,另一种可能的方法是为每个租户简单地拥有一个引擎实例:

截图-2015-10-06-13.12.56

在此设置中,每个租户可以具有不同的资源配置,甚至可以在不同的物理服务器上运行。 当然,此图中的每个引擎可以是多个引擎,以提高性能/故障转移/等等。 现在的好处是,资源是为租户量身定制的。 缺点是设置比较复杂(多个数据库架构,每个租户都有不同的配置文件,等等)。 每个引擎实例都将占用内存(但是Activiti会占用很少的内存)。 另外,您无需编写一些路由组件 ,就可以以某种方式知道当前租户上下文并路由到正确的引擎。

截图-2015-10-06-13.18.36-300x206

多架构多租户

Activiti多租户故事的最新添加是在两周前添加的(这是commit ),同时是版本5和6的添加。这里,每个租户都有一个数据库(模式),但只有一个引擎实例。 再次,在实践中,可能有多个用于性能/故障转移/实例的实例,但是概念是相同的:

截图-2015-10-06-13.41.20

好处显而易见:只有一个引擎实例可以管理和配置,而且API与非多租户引擎完全相同。 但最重要的是,租户的数据与其他租户的数据完全分开。 缺点(类似于多引擎多租户方法)是有人需要管理和配置不同的数据库。 但是复杂的引擎管理已不复存在。

我上面链接到的提交还包含一个单元测试 ,该测试显示了多模式多租户引擎的工作方式。

构建流程引擎很容易,因为有一个MultiSchemaMultiTenantProcessEngineConfiguration可抽象出大多数细节:

config = new MultiSchemaMultiTenantProcessEngineConfiguration(tenantInfoHolder);config.setDatabaseType(MultiSchemaMultiTenantProcessEngineConfiguration.DATABASE_TYPE_H2);
config.setDatabaseSchemaUpdate(MultiSchemaMultiTenantProcessEngineConfiguration.DB_SCHEMA_UPDATE_DROP_CREATE);config.registerTenant("alfresco", createDataSource("jdbc:h2:mem:activiti-mt-alfresco;DB_CLOSE_DELAY=1000", "sa", ""));
config.registerTenant("acme", createDataSource("jdbc:h2:mem:activiti-mt-acme;DB_CLOSE_DELAY=1000", "sa", ""));
config.registerTenant("starkindustries", createDataSource("jdbc:h2:mem:activiti-mt-stark;DB_CLOSE_DELAY=1000", "sa", ""));processEngine = config.buildProcessEngine();

这看起来与启动常规Activiti流程引擎实例非常相似。 主要区别在于我们是使用引擎注册租户。 每个租户都需要添加其唯一的租户标识符和数据源实现。 当然,数据源实现需要有自己的连接池。 这意味着您可以根据使用情况有效地为某些租户提供不同的连接池配置。 Activiti引擎将确保已创建或验证每个数据库架构都是正确的。

魔术以使这一切工作是TenantAwareDataSource 。 这是一个javax.sql.DataSource实现,它根据当前租户标识符委托给正确的数据源。 此类的想法在很大程度上受到Spring的AbstractRoutingDataSource (站在其他开源项目的肩膀上!)的影响。

通过从TenantInfoHolder实例获取当前的租户标识符 ,可以路由到正确的数据源。 正如您在上面的代码片段中看到的那样,在构造MultiSchemaMultiTenantProcessEngineConfiguration时,这也是必需的参数。 TenantInfoHolder是您需要实现的接口,具体取决于您环境中用户和租户的管理方式。 通常,您将使用ThreadLocal来存储由某些安全过滤器填充的当前用户/租户信息(类似于Spring Security)。 该类有效地充当下图中的路由组件”:

截图-2015-10-06-13.53.131

在单元测试示例中,我们确实使用ThreadLocal来存储当前的租户标识符 ,并用一些演示数据填充它:

private void setupTenantInfoHolder() {DummyTenantInfoHolder tenantInfoHolder = new DummyTenantInfoHolder();tenantInfoHolder.addTenant("alfresco");tenantInfoHolder.addUser("alfresco", "joram");tenantInfoHolder.addUser("alfresco", "tijs");tenantInfoHolder.addUser("alfresco", "paul");tenantInfoHolder.addUser("alfresco", "yvo");tenantInfoHolder.addTenant("acme");tenantInfoHolder.addUser("acme", "raphael");tenantInfoHolder.addUser("acme", "john");tenantInfoHolder.addTenant("starkindustries");tenantInfoHolder.addUser("starkindustries", "tony");this.tenantInfoHolder = tenantInfoHolder;}

现在,我们开始一些流程实例,同时还要切换当前的租户标识符。 在实践中,您必须想象多个线程随请求一起进入,并且它们将根据登录的用户设置当前的租户标识符:

startProcessInstances("joram");
startProcessInstances("joram");
startProcessInstances("raphael");
completeTasks("raphael");

上面的startProcessInstances方法将使用标准Activiti API设置当前用户和租户标识符,并启动几个流程实例, 就好像根本没有多租户一样completeTasks方法类似地完成了一些任务)。

同样很酷的是, 您可以通过使用与构建流程引擎时相同的方法来动态注册(和删除)新的租户 。 Activiti引擎将确保已创建或验证数据库架构。

config.registerTenant("dailyplanet", createDataSource("jdbc:h2:mem:activiti-mt-daily;DB_CLOSE_DELAY=1000", "sa", ""));

这是一部电影,显示正在运行的单元测试以及有效隔离的数据:

多租户执行器

最后一个难题是工作执行者。 常规Activiti API调用“借用”当前线程以执行其操作,因此可以使用之前在该线程上设置的任何用户/租户上下文。

但是,作业执行程序使用后台线程池运行,并且没有此类上下文。 由于Activiti中的AsyncExecutor是一个接口,因此实现多模式多租户作业执行器并不难。 当前,我们添加了两个实现。 第一个实现称为SharedExecutorServiceAsyncExecutor

config.setAsyncExecutorEnabled(true);
config.setAsyncExecutorActivate(true);
config.setAsyncExecutor(new SharedExecutorServiceAsyncExecutor(tenantInfoHolder));

此实现(顾名思义)对所有租户使用一个线程池。 每个租户确实有其自己的作业获取线程,但是一旦获取了作业,便将其放到共享线程池中。 该系统的好处是Activiti使用的线程数受到限制。

第二种实现称为ExecutorPerTenantAsyncExecutor

config.setAsyncExecutorEnabled(true);
config.setAsyncExecutorActivate(true);
config.setAsyncExecutor(new ExecutorPerTenantAsyncExecutor(tenantInfoHolder));

顾名思义,该类充当“代理” AsyncExecutor。 对于每个注册的租户,将启动完整的默认AsyncExecutor。 每个都有自己的获取线程和执行线程池。 “代理”仅委托给正确的AsyncExecutor实例。 这种方法的好处是,每个租户都可以根据租户的需求进行细粒度的作业执行者配置。

结论

一如既往,欢迎所有反馈。 放手多方案多租户,让我们知道您的想法以及将来可以改进的地方!

翻译自: https://www.javacodegeeks.com/2015/10/multi-tenancy-with-separate-database-schemas-in-activiti.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/356614.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

html5自动把某个层放在屏幕底部,告诉你一个将 footer 保持在底部的最好方法

当你在布局网页时,有可能会遇到类似下面的这种情况broken_layout.png导致这一问题的原因是页面内容太少,无法将内容区域撑开,从而在 footer 下面留下一大块空白。本文将介绍一种现代化的方法,�确保 footer 始终处于页面…

html的扇形代码导航,CSS3--利用transform和transition属性制作扇形导航

在前面,我们已经讲解了transform这个属性以及案例,那么本文会进一步结合transform和transition两个属性,并制作一个简单的案例进行说明。一、transition属性说明接下来简单分析一下transition这个属性的定义以及子属性。1)ansition-property …

常见的误解:这会创建多少个对象?

总览 一个常见的问题是一段代码创建多少个对象或多少个字符串。 答案通常不是您的想法,也不是您真正需要知道的。 了解何时创建对象是很有用的,但是有很多其他因素通常要考虑的重要得多,这可能意味着应用程序总数不是您所想的。 字符串不是一…

cvs配电保护断路器_电工电器(三)-配电电器-断路器类-剩余电流保护断路器

本文文字836,阅读时间6分钟左右。此系列文章 从配电电器的大类等进行慢慢阐述,有不足的地方 欢迎大家相互探讨交流。配电电器,顾名思义就是进行电力分配的设备。电,从发电机出来之后,由总线输出,不可能直接…

delhpi7 tcombobox清楚重复项_专利数据统计中需要搞清楚的首要问题(2)

上一篇专利数据统计中需要搞清楚的首要问题(1)介绍了通过合并申请号避免重复统计,理清了专利篇数和专利件数的问题,那么还有一类统计就是对发明项数的统计,这里就涉及到对同一项发明的重复统计问题。上一篇介绍的相同申请号但不同公开号的专利…

【Electron】Electron开发入门(八):自定义electron框架外壳(shell)的菜单(Menu)...

1.自定义electron框架外壳(shell)的菜单(Menu) electron的main.js里代码: const Menu require(electron).Menu; var template [{label: 关闭,click: function () { win.close();console.log("关闭")},// s…

交通大数据应用细分_盈海科技 | 交通大数据可视化“掘金”数据价值

面对日益拥堵的交通状况智能交通布局虽在不断完善但交通管理依旧收效甚微问题究竟出在了哪里?数据独立存储难以融合应用数据内在规律难寻数据可视化程度低……问题繁多 困难重重怎么办???交通大数据可视化解决方案上岗啦&#xff…

书评– Kubernetes Up&Running,作者:Kelsey Hightower

欢呼! 正如我在以前的帖子中所写的那样,当您开始研究和使用所有这些新颖的,有光泽的容器/编排技术时,很有可能最终导致您的翻译“迷失”。 很多信息,很多技术,很多开发 ,很多承诺,很…

MFC CListCtrl

列名、行内容的添加、删除。 据列名、行内容长度设置列宽。 排序。 提升权限 BOOL CDemoListCtrlApp::EnableDebugPrivilege() { HANDLE token; if(!OpenProcessToken(GetCurrentProcess(),TOKEN_ADJUST_PRIVILEGES,&token)) { return FALSE; } TOKEN_PRIVILEGES tkp…

快手用旺旺瓶子做机器人_100品牌入榜,在快手的品牌运营怎么做?|11月快手品牌新势力榜揭晓...

11月榜单见证了许多新入驻快手的品牌迅速成长。母婴品牌「安慕斯」实现垂类专业场景剧情化,引起用户发注,激发用户参与,单月涨粉突破60万;服饰箱包运动垂类下的珠宝品牌「DR钻戒」以“一生唯一真爱”的理念抢占消费者心智&#xf…

认识计算机ppt课件游戏,《认识计算机》PPT课件

《认识计算机》PPT课件 认知主义认为 学习是个体对环 境的作用,而并不仅是环境刺激引起的行为改变;环境只能提供潜在刺激,至于这些潜在刺激是否受到注意或被加工,这主要取决于学习者内部的认知结构。 认 识 计 算 机 认知主义认为…

BZOJ1433 ZJOI2009 假期的宿舍 二分图匹配

1433: [ZJOI2009]假期的宿舍 Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 2375 Solved: 1005[Submit][Status][Discuss]Description Input Output Sample Input 1 3 1 1 0 0 1 0 0 1 1 1 0 0 1 0 0Sample Output ˆ ˆHINT 对于30% 的数据满足1 ≤ n ≤ 12。对于100% 的…

Apache Spark中实现的MapReduce设计模式

该博客是该系列文章的第一篇,讨论了MapReduce设计模式一书中的一些设计模式,并展示了如何在Apache Spark(R)中实现这些模式。 在编写MapReduce或Spark程序时,考虑执行作业的数据流很有用。 即使Pig,Hive&a…

计算机主机风扇安装方法,电脑机箱怎么安装风扇减震胶钉保护主板cup?

炎炎夏日,是时候给你的爱机清清灰,特别是对于机箱散热不好的朋友就需要给电脑机箱装上几个风力强劲的风扇,这样可以大大减少CPU、主板等的老化时间,延长爱机的寿命。现在机箱风扇大都使用橡胶拉钉(或者叫减震钉、固定钉)安装&…

2个css特效冲突了怎么办_患上类风湿病怎么办?2个方法拿走不谢

类风湿是一种常见的疾病,类风湿关节炎简称为类风湿,是一个累及周围关节为主的多系统性炎症性自身免疫病,患者的关节疼痛、肿胀,而且易反复发作。那么,得了类风湿病怎么办?得了类风湿病怎么办目前&#xff0…

将项目导入eclipse中出现的jsp页面报错

图片摘自百度经验&#xff0c;实在是每次都会忘了步骤&#xff0c;每次都得重新百度&#xff0c;所以索性自己总结到博客中&#xff0c;下次如果还记不住就直接从博客中看。原谅我实在学渣&#xff0c;呜呜~~~~(>_<)~~~~ 转载于:https://www.cnblogs.com/yangyufan/p/600…

怎样让计算机恢复到桌面上,如何把电脑桌面恢复成原样.怎么办?

此方案适用XP\VISTA\WIN7系统【问题描述】&#xff1a;桌面图标太多【原因分析】&#xff1a;1.下载的软件快捷方式放到桌面没有进行整理;2.在桌面上放置太多的文件【简易步骤】&#xff1a;【360安全卫士】—【功能大全】—【桌面管理】—【整理桌面个人资料】【解决方案】&am…

中装订线位置_企业宣传画册、产品目录常用的装订方法

印刷是个专业活&#xff0c;特别是画报、画册这些种类多&#xff0c;要求高。下面介绍一下最常用到的三种装订方法&#xff1a;骑马订骑马订(saddlestitch)英文是马鞍的意思&#xff0c;取其于装订之时&#xff0c;将摺好的页子如同为马匹上鞍一般的动作&#xff0c;配至装订机…

使用Hibernate在CQRS读取模型中进行快速开发

在这篇文章中&#xff0c;我将分享一些在CQRS读取模型中使用Hibernate工具进行快速开发的技巧。 为什么要休眠&#xff1f; 休眠非常流行。 从外观上看&#xff0c;它也很容易&#xff0c;而从内部看&#xff0c;它却相当复杂。 它可以很容易地开始使用&#xff0c;而无需进行…

美国东北大学khoury计算机学院,2021年美国东北大学计算机研究生专业有哪些?入学要求高吗?...

在“唯才是用”的时代&#xff0c;高新科技行业人才成为了社会的主流&#xff0c;各行各业也都急需计算机相关人才&#xff0c;美国可谓是计算机领域的鼻祖&#xff0c;拥有着非常先进的互联网技术&#xff0c;除此之外&#xff0c;几乎每所大学都开设了计算机专业&#xff0c;…