使用多租户时的 Spring Boot 范围问题

Posted

技术标签:

【中文标题】使用多租户时的 Spring Boot 范围问题【英文标题】:Spring boot scope issue when using multitenancy 【发布时间】:2015-09-20 11:46:49 【问题描述】:

我尝试使用此答案中的代码为我的 spring boot 1.2.5 添加多租户:

Setting up a MultiTenantConnectionProvider using Hibernate 4.2 and Spring 3.1.1

我得到以下异常:

Caused by: java.lang.IllegalStateException: No thread-bound request found: Are you referring to request attributes outside of an actual web request, or processing a request outside of the originally receiving thread? If you are actually operating within a web request and still receive this message, your code is probably running outside of DispatcherServlet/DispatcherPortlet: In this case, use RequestContextListener or RequestContextFilter to expose the current request.
        at org.springframework.web.context.request.RequestContextHolder.currentRequestAttributes(RequestContextHolder.java:131)
        at org.springframework.web.context.request.AbstractRequestAttributesScope.get(AbstractRequestAttributesScope.java:41)
        at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:337)

上述答案的源代码是:

@Component
@Scope(value = "request", proxyMode = ScopedProxyMode.TARGET_CLASS)
public class RequestURITenantIdentifierResolver implements CurrentTenantIdentifierResolver 
    @Autowired
    private HttpServletRequest request;
    @Override
    public String resolveCurrentTenantIdentifier() 
        String[] pathElements = request.getRequestURI().split("/");
        String tenant = pathElements[1];
        return tenant;
    
    @Override
    public boolean validateExistingCurrentSessions() 
        return true;
    

我尝试将范围值更改为原型:

@Scope(value = "prototype", proxyMode = ScopedProxyMode.TARGET_CLASS)

在我尝试在我的 JpaRepository 中使用 @Query 之前效果很好,例如:

@Query("From Order where orderId = :id")
public Order joinWithPurchaseItems(@Param("id") Integer id);

它会抛出同样的异常:

Caused by: java.lang.IllegalStateException: No thread-bound request found: Are you referring to request attributes outside of an actual web request, or processing a request outside of the originally receiving thread? If you are actually operating within a web request and still receive this message, your code is probably running outside of DispatcherServlet/DispatcherPortlet: In this case, use RequestContextListener or RequestContextFilter to expose the current request.
        at org.springframework.web.context.request.RequestContextHolder.currentRequestAttributes(RequestContextHolder.java:131)
        at org.springframework.web.context.request.AbstractRequestAttributesScope.get(AbstractRequestAttributesScope.java:41)
        at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:337)

有趣的是,使用本机查询不会引发此异常。

我还尝试在我的 Application 类中使用 RequestContextListener,但没有成功:

@SpringBootApplication
public class Application 

    @Bean
    @ConditionalOnMissingBean(RequestContextListener.class)
    public RequestContextListener requestContextListener() 
        return new RequestContextListener();
     

    public static void main(String[] args) 
        SpringApplication.run(Application.class, args);
    

感谢任何帮助。

【问题讨论】:

请求范围不起作用。删除范围。而是使用RequestContextHolder 来获取RequestContext 并在上下文中使用getRequest。或使用Filter 将某些内容放入ThreadLocal 并让您的CurrentTenantIdentifierResolver 使用ThreadLocal。示例代码可以在here 找到。额外的优点是它更通用,您还可以将它用于主题、资源加载等。 过滤方法运行良好。谢谢!我查看了示例代码,它有一些有趣的功能,我认为如果它有更多的文档将会非常有用.. 【参考方案1】:

正如评论中所建议的,我改用过滤器并从那里捕获 URL。解析器从过滤器设置的静态字段中捕获架构名称。

【讨论】:

以上是关于使用多租户时的 Spring Boot 范围问题的主要内容,如果未能解决你的问题,请参考以下文章

Spring Boot - 多租户 - 优化 API 的响应时间

Spring Boot 中的多租户

Spring Boot Keycloak 多租户配置

Spring Boot 构建多租户SaaS平台核心技术指南

Spring Boot 构建多租户SaaS平台核心技术指南

Spring Boot 构建多租户SaaS平台核心技术指南