diff --git a/fund-common/src/main/java/com/fundplatform/common/config/TenantRoutingProperties.java b/fund-common/src/main/java/com/fundplatform/common/config/TenantRoutingProperties.java
index f6b2ce7..3f3e459 100644
--- a/fund-common/src/main/java/com/fundplatform/common/config/TenantRoutingProperties.java
+++ b/fund-common/src/main/java/com/fundplatform/common/config/TenantRoutingProperties.java
@@ -3,14 +3,32 @@ package com.fundplatform.common.config;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
-import java.util.Arrays;
-import java.util.List;
-import java.util.Map;
-import java.util.HashMap;
+import java.util.*;
+
+/**
+ * 多租户路由配置属性
+ *
+ *
支持从 YAML 配置文件读取租户路由配置
+ *
+ * 配置示例:
+ *
+ * tenant:
+ * routing:
+ * enabled: true
+ * default-tenant-id: 1
+ * services:
+ * fund-sys:
+ * vip-tenants:
+ * - TENANT_VIP_001
+ * fallback-to-shared: true
+ *
+ */
+@Component
+@ConfigurationProperties(prefix = "tenant.routing")
public class TenantRoutingProperties {
/** 是否启用租户路由 */
- private boolean enabled = false;
+ private boolean enabled = true;
/** 租户 ID 请求头 */
private String tenantHeader = "X-Tenant-Id";
@@ -21,6 +39,9 @@ public class TenantRoutingProperties {
/** 服务组分隔符 */
private String groupSeparator = "TENANT_";
+ /** 默认租户 ID(当未指定时使用) */
+ private String defaultTenantId = "1";
+
/** 共享服务列表(不区分租户,所有租户共用) */
private List sharedServices = Arrays.asList(
"fund-gateway",
@@ -28,10 +49,10 @@ public class TenantRoutingProperties {
"fund-file"
);
- /** 默认租户 ID(当未指定时使用) */
- private String defaultTenantId = "1";
-
/** 租户服务配置映射 */
+ private Map services = new HashMap<>();
+
+ /** 租户服务配置(旧版兼容) */
private Map tenantConfigs = new HashMap<>();
// Getters and Setters
@@ -68,6 +89,14 @@ public class TenantRoutingProperties {
this.groupSeparator = groupSeparator;
}
+ public String getDefaultTenantId() {
+ return defaultTenantId;
+ }
+
+ public void setDefaultTenantId(String defaultTenantId) {
+ this.defaultTenantId = defaultTenantId;
+ }
+
public List getSharedServices() {
return sharedServices;
}
@@ -76,12 +105,12 @@ public class TenantRoutingProperties {
this.sharedServices = sharedServices;
}
- public String getDefaultTenantId() {
- return defaultTenantId;
+ public Map getServices() {
+ return services;
}
- public void setDefaultTenantId(String defaultTenantId) {
- this.defaultTenantId = defaultTenantId;
+ public void setServices(Map services) {
+ this.services = services;
}
public Map getTenantConfigs() {
@@ -109,21 +138,76 @@ public class TenantRoutingProperties {
return sharedServices.contains(serviceName);
}
+ /**
+ * 获取服务的 VIP 租户列表
+ */
+ public List getVipTenants(String serviceName) {
+ TenantServiceConfig config = services.get(serviceName);
+ if (config != null && config.getVipTenants() != null) {
+ return config.getVipTenants();
+ }
+ return Collections.emptyList();
+ }
+
+ /**
+ * 判断租户是否为某个服务的 VIP 租户
+ */
+ public boolean isVipTenant(String serviceName, String tenantGroup) {
+ if (tenantGroup == null || tenantGroup.isEmpty()) {
+ return false;
+ }
+ List vipTenants = getVipTenants(serviceName);
+ return vipTenants.contains(tenantGroup);
+ }
+
+ /**
+ * 判断服务是否启用了共享实例回退
+ */
+ public boolean isFallbackToShared(String serviceName) {
+ TenantServiceConfig config = services.get(serviceName);
+ if (config != null) {
+ return config.isFallbackToShared();
+ }
+ return true; // 默认启用回退
+ }
+
/**
* 租户服务配置
*/
public static class TenantServiceConfig {
+ /** VIP 租户列表(优先路由到专属实例) */
+ private List vipTenants = new ArrayList<>();
+
+ /** 是否回退到共享实例 */
+ private boolean fallbackToShared = true;
+
/** 租户 ID */
private String tenantId;
/** 服务实例配置 */
- private Map services = new HashMap<>();
+ private Map instances = new HashMap<>();
/** 数据库配置(一库一租户模式) */
private DatabaseConfig database;
// Getters and Setters
+ public List getVipTenants() {
+ return vipTenants;
+ }
+
+ public void setVipTenants(List vipTenants) {
+ this.vipTenants = vipTenants != null ? vipTenants : new ArrayList<>();
+ }
+
+ public boolean isFallbackToShared() {
+ return fallbackToShared;
+ }
+
+ public void setFallbackToShared(boolean fallbackToShared) {
+ this.fallbackToShared = fallbackToShared;
+ }
+
public String getTenantId() {
return tenantId;
}
@@ -132,12 +216,12 @@ public class TenantRoutingProperties {
this.tenantId = tenantId;
}
- public Map getServices() {
- return services;
+ public Map getInstances() {
+ return instances;
}
- public void setServices(Map services) {
- this.services = services;
+ public void setInstances(Map instances) {
+ this.instances = instances;
}
public DatabaseConfig getDatabase() {
diff --git a/fund-gateway/src/main/resources/application-docker.yml b/fund-gateway/src/main/resources/application-docker.yml
index 56b4b87..fb36099 100644
--- a/fund-gateway/src/main/resources/application-docker.yml
+++ b/fund-gateway/src/main/resources/application-docker.yml
@@ -17,12 +17,22 @@ spring:
namespace: ${NACOS_NAMESPACE:}
group: DEFAULT_GROUP
enabled: true
+ metadata:
+ service-type: gateway
gateway:
discovery:
locator:
enabled: true
lower-case-service-id: true
+ # 全局跨域配置
+ globalcors:
+ cors-configurations:
+ '[/**]':
+ allowed-origins: "*"
+ allowed-methods: "*"
+ allowed-headers: "*"
+ allow-credentials: true
routes:
- id: fund-sys
uri: lb://fund-sys
@@ -30,6 +40,7 @@ spring:
- Path=/api/sys/**
filters:
- StripPrefix=1
+ # 租户感知负载均衡(自动添加 tenant-group 请求头)
- id: fund-cust
uri: lb://fund-cust
predicates:
@@ -75,8 +86,46 @@ spring:
# JWT 配置
jwt:
- secret: YourSecretKeyForJWTTokenGenerationMustBeAtLeast256BitsLong
- expiration: 86400000
+ secret: ${JWT_SECRET:YourSecretKeyForJWTTokenGenerationMustBeAtLeast256BitsLong}
+ expiration: ${JWT_EXPIRATION:86400000}
+
+# ==================== 多租户混合模式配置 ====================
+tenant:
+ routing:
+ # 启用租户感知负载均衡
+ enabled: true
+ # 默认租户ID
+ default-tenant-id: 1
+ # 租户服务配置(定义每个服务的VIP租户)
+ services:
+ fund-sys:
+ vip-tenants:
+ - TENANT_VIP_001
+ - TENANT_VIP_002
+ fallback-to-shared: true
+ fund-cust:
+ vip-tenants:
+ - TENANT_VIP_001
+ fallback-to-shared: true
+ fund-proj:
+ vip-tenants:
+ - TENANT_VIP_001
+ fallback-to-shared: true
+ fund-req:
+ vip-tenants: []
+ fallback-to-shared: true
+ fund-exp:
+ vip-tenants: []
+ fallback-to-shared: true
+ fund-receipt:
+ vip-tenants: []
+ fallback-to-shared: true
+ fund-report:
+ vip-tenants: []
+ fallback-to-shared: true
+ fund-file:
+ vip-tenants: []
+ fallback-to-shared: true
# Actuator 监控端点配置
management:
@@ -98,6 +147,7 @@ management:
metrics:
tags:
application: ${spring.application.name}
+ service-type: gateway
distribution:
percentiles-histogram:
http.server.requests: true
@@ -109,5 +159,8 @@ logging:
level:
root: INFO
com.fundplatform: DEBUG
+ # 多租户负载均衡日志
+ com.fundplatform.common.loadbalancer: DEBUG
+ com.fundplatform.gateway.filter: DEBUG
pattern:
- console: "%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] [%X{traceId}] %-5level %logger{36} - %msg%n"
+ console: "%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] [%X{traceId}] [%X{tenantId}] %-5level %logger{36} - %msg%n"
diff --git a/fund-sys/src/main/resources/application-docker.yml b/fund-sys/src/main/resources/application-docker.yml
index 642df80..3144570 100644
--- a/fund-sys/src/main/resources/application-docker.yml
+++ b/fund-sys/src/main/resources/application-docker.yml
@@ -38,6 +38,12 @@ spring:
namespace: ${NACOS_NAMESPACE:}
group: DEFAULT_GROUP
enabled: true
+ # 多租户元数据配置(支持混合模式负载均衡)
+ metadata:
+ tenant-id: ${TENANT_ID:1}
+ tenant-group: ${TENANT_GROUP:}
+ # 服务实例权重(VIP实例可配置更高权重)
+ weight: ${NACOS_WEIGHT:1}
# MyBatis Plus 配置
mybatis-plus:
@@ -49,6 +55,31 @@ mybatis-plus:
logic-delete-value: 1
logic-not-delete-value: 0
+# ==================== 多租户混合模式配置 ====================
+tenant:
+ routing:
+ # 启用租户感知负载均衡
+ enabled: true
+ # 默认租户ID
+ default-tenant-id: 1
+ # 租户服务配置
+ services:
+ fund-sys:
+ # VIP租户列表(优先路由到专属实例)
+ vip-tenants:
+ - TENANT_VIP_001
+ - TENANT_VIP_002
+ # 共享实例回退策略:当无专属实例时回退到共享实例
+ fallback-to-shared: true
+ fund-cust:
+ vip-tenants:
+ - TENANT_VIP_001
+ fallback-to-shared: true
+ fund-proj:
+ vip-tenants:
+ - TENANT_VIP_001
+ fallback-to-shared: true
+
# Actuator 监控端点配置
management:
endpoints:
@@ -69,6 +100,10 @@ management:
metrics:
tags:
application: ${spring.application.name}
+ # 多租户监控标签
+ tenant_id: ${TENANT_ID:1}
+ tenant_group: ${TENANT_GROUP:shared}
+ instance_type: ${TENANT_GROUP:shared}
distribution:
percentiles-histogram:
http.server.requests: true
@@ -80,5 +115,8 @@ logging:
level:
root: INFO
com.fundplatform: DEBUG
+ # 多租户负载均衡日志
+ com.fundplatform.common.loadbalancer: DEBUG
+ com.fundplatform.common.nacos: DEBUG
pattern:
- console: "%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] [%X{traceId}] %-5level %logger{36} - %msg%n"
+ console: "%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] [%X{traceId}] [%X{tenantId}] %-5level %logger{36} - %msg%n"