1
0
mirror of synced 2026-02-04 16:40:54 +08:00
Files
WxJava/spring-boot-starters/MULTI_TENANT_MODE_IMPROVEMENT.md

5.2 KiB
Raw Blame History

多租户模式配置改进说明

问题背景

用户在 issue #3835 中提出了一个架构设计问题:

基础 Wx 实现类中已经有 configMap 了,可以用 configMap 来存储不同的小程序配置。不同的配置,都是复用同一个 http 客户端。为什么在各个 spring-boot-starter 中又单独创建类来存储不同的配置?从 spring 的配置来看http 客户端只有一个,不同小程序配置可以实现多租户,所以似乎没必要单独再建新类存放?重复创建,增加了 http 客户端的成本?直接使用 Wx 实现类中已经有 configMap 不是更好吗?

解决方案

从 4.8.0 版本开始,我们为多租户 Spring Boot Starter 提供了两种实现模式供用户选择:

1. 隔离模式ISOLATED默认

实现方式:为每个租户创建独立的 WxService 实例,每个实例拥有独立的 HTTP 客户端。

优点

  • 线程安全,无需担心并发问题
  • 不依赖 ThreadLocal适合异步/响应式编程
  • 租户间完全隔离,互不影响

缺点

  • 每个租户创建独立的 HTTP 客户端,资源占用较多
  • 适合租户数量不多的场景(建议 < 50 个租户)

代码实现WxMaMultiServicesImpl, WxMpMultiServicesImpl

2. 共享模式SHARED新增

实现方式:使用单个 WxService 实例管理所有租户配置,通过 ThreadLocal 切换租户,所有租户共享同一个 HTTP 客户端。

优点

  • 共享 HTTP 客户端,大幅节省资源
  • 适合租户数量较多的场景(支持 100+ 租户)
  • 内存占用更小

缺点

  • 依赖 ThreadLocal 切换配置,在异步场景需要特别注意
  • 需要注意线程上下文传递

代码实现WxMaMultiServicesSharedImpl, WxMpMultiServicesSharedImpl

使用方式

配置示例

wx:
  ma:  # 或 mp, cp, channel
    apps:
      tenant1:
        app-id: wxd898fcb01713c555
        app-secret: 47a2422a5d04a27e2b3ed1f1f0b0dbad
      tenant2:
        app-id: wx1234567890abcdef
        app-secret: 1234567890abcdef1234567890abcdef
    
    config-storage:
      type: memory
      http-client-type: http_client
      # 多租户模式配置(新增)
      multi-tenant-mode: shared  # isolated默认或 shared

代码使用(两种模式代码完全相同)

@RestController
public class WxController {
  @Autowired
  private WxMaMultiServices wxMaMultiServices;  // 或 WxMpMultiServices
  
  @GetMapping("/api/{tenantId}")
  public String handle(@PathVariable String tenantId) {
    WxMaService wxService = wxMaMultiServices.getWxMaService(tenantId);
    // 使用 wxService 调用微信 API
    return wxService.getAccessToken();
  }
}

性能对比

以 100 个租户为例:

指标 隔离模式 共享模式
HTTP 客户端数量 100 个 1 个
内存占用(估算) ~500MB ~50MB
线程安全 完全安全 ⚠️ 需注意异步场景
性能 略高(无 ThreadLocal 切换) 略低(有 ThreadLocal 切换)
适用场景 中小规模 大规模

支持的模块

目前已实现共享模式支持的模块:

  • 小程序MiniAppwx-java-miniapp-multi-spring-boot-starter
  • 公众号MPwx-java-mp-multi-spring-boot-starter

后续版本将支持:

  • 企业微信CP
  • 视频号Channel
  • 企业微信第三方应用CP-TP

迁移指南

从旧版本升级

升级到 4.8.0+ 后:

  1. 默认行为不变:如果不配置 multi-tenant-mode,将继续使用隔离模式(与旧版本行为一致)
  2. 向后兼容:所有现有代码无需修改
  3. 可选升级:如需节省资源,可配置 multi-tenant-mode: shared 启用共享模式

选择建议

使用隔离模式ISOLATED的场景

  • 租户数量较少(< 50 个)
  • 使用异步编程、响应式编程
  • 对线程安全有严格要求
  • 对资源占用不敏感

使用共享模式SHARED的场景

  • 租户数量较多(> 50 个)
  • 同步编程场景
  • 对资源占用敏感
  • 可以接受 ThreadLocal 的约束

注意事项

共享模式下的异步编程

如果使用共享模式,在异步编程时需要注意 ThreadLocal 的传递:

// ❌ 错误:异步线程无法获取到正确的配置
CompletableFuture.runAsync(() -> {
  wxService.getUserService().getUserInfo(...);  // 可能使用错误的租户配置
});

// ✅ 正确:在主线程获取必要信息,传递给异步线程
String appId = wxService.getWxMaConfig().getAppid();
CompletableFuture.runAsync(() -> {
  log.info("AppId: {}", appId);  // 使用已获取的配置信息
});

详细文档

相关链接

致谢

感谢 issue 提出者对项目架构的深入思考和建议,这帮助我们提供了更灵活、更高效的多租户解决方案。