使用Spring和Hibernate以及Tomcat

时间:2017-03-09 01:00:28

标签: java spring hibernate tomcat multi-tenant

我正在尝试了解如何为涉及多租户的SaaS产品构建RESTful API。技术堆栈是使用Spring和Hibernate并将WAR部署到Tomcat的Java。

我的主要问题是我们如何在REST调用中维护tenant_id,以便应用程序在执行CRUD时使用正确的数据库连接。看到Tomcat使用线程池并重用线程,我们不应该使用ThreadLocal。

我已经读过slf4j支持使用MDC实现进行日志记录。 servlet过滤器会提前维护tenant_id并在过滤器退出时将其清除。因此,记录器在消息中使用正确的tenant_id。

同时使用ThreadLocal违反了无状态原则,因为这会隐式添加状态。

此外,创建某种ContextTession对象持有tenant_id并传递它的想法似乎并没有解决我的问题。由于此对象将向下传递DAL和DAO的层以加载对象。我想在这个ContextSession类上避免这种高耦合,并且必须将它包含在许多方法签名上。

如何在无状态环境中实施多租户?

2 个答案:

答案 0 :(得分:0)

当用户登录您的应用程序时,他们会以某种方式与租户相关联。因此,租户信息应该可以从Spring SecurityContext访问。

例如,如果我有2个租户的申请;租户A和租户B.登录时,用户需要以某种方式指示他们属于哪个租户。这可以通过各种方式完成,例如使用不同的主机名(例如tenantA.myapp.com,tenantB.myapp.com)或url参数,或在登录表单上输入租户信息。在验证用户身份时,您需要使用与特定租户关联的身份验证领域。作为身份验证的一部分,应设置spring SecurityContext以包含允许您在用户的后续服务调用中确定用户所属的租户的信息。应该可以从应用程序的不同服务层访问SecurityContext,而无需为此事先明确编写任何内容。

答案 1 :(得分:0)

有多种方法可以将您当前的HttpSession与特定租户相关联。

  1. 在URL上提供某种类型的client_id参数,用于通过集中式公共客户端数据库反向查找指定的后端tenant

  2. 将经过身份验证的用户与特定tenant相关联。当用户针对集中用户数据库进行身份验证时,将根据用户帐户查找租户。

  3. 如何将tenant_id传递给较低的应用程序层实际上是一个品味问题。

    我的第一个选择是使用ThreadLocal。如果您已经在使用Spring Security,那么您已经在使用ThreadLocal个变量,甚至可能都不知道它。

    使用ThreadLocal变量不会破坏应用程序的无状态设计。您只需拥有一些代码,期望变量包含必须使用的特定值。它只是一种在应用程序层之间传递状态而不实际将其作为方法签名上的参数传递的奇特方式。

    显然,其他两个选项是使用一些 Context 对象或仅直接传递给下游的值。

    在Web应用程序中,我通常会通过一些拦截器或过滤器来执行此操作,该拦截器或过滤器将按请求查找请求参数client_id并获取关联的tenantId并将其设置为特殊ThreadLocal变量。

    一旦对chain.doFilter( request, response );的调用返回或抛出异常,您只需清除ThreadLocal变量。