refactor: 简化多租户路由配置,基于 Nacos 元数据动态匹配

问题:tenant.routing.services 配置在每个服务中重复定义 vip-tenants

解决方案:
1. TenantRoutingProperties 简化
   - 移除 services 映射(vip-tenants 列表)
   - 保留全局配置:enabled, fallback-to-shared, shared-services
   - 路由逻辑改为基于实例元数据动态匹配

2. 配置简化
   - Gateway: 只需全局配置,无需定义各服务的 vip-tenants
   - 服务实例: 只需在 Nacos metadata 中声明 tenant-group
   - 负载均衡器: 从实例 metadata 读取 tenant-group 进行匹配

3. 架构变化
   修改前:配置文件定义 vip-tenants 列表
   修改后:实例注册时声明 tenant-group,负载均衡器动态匹配

示例:
  共享实例 metadata: { tenant-group: "" }
  VIP 实例 metadata: { tenant-group: "TENANT_VIP_001" }
  请求匹配 → 路由到对应实例
This commit is contained in:
zhangjf 2026-02-19 21:18:58 +08:00
parent 2765f3f265
commit 330ec6dea9
17 changed files with 136 additions and 286 deletions

View File

@ -3,24 +3,36 @@ package com.fundplatform.common.config;
import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import java.util.*; import java.util.Arrays;
import java.util.List;
/** /**
* 多租户路由配置属性 * 多租户路由配置属性
* *
* <p>支持从 YAML 配置文件读取租户路由配置</p> * <p>租户路由基于 Nacos 服务实例的 metadata.tenant-group 元数据进行匹配</p>
* *
* <p>配置示例</p> * <h3>工作原理</h3>
* <pre>
* 1. 服务实例注册到 Nacos metadata 中声明 tenant-group
* - 共享实例: tenant-group 为空或不存在
* - VIP 实例: tenant-group = "TENANT_VIP_001"
*
* 2. Gateway 从请求中提取租户组负载均衡器匹配实例元数据
* - 请求 tenantGroup = "TENANT_VIP_001" 路由到匹配的 VIP 实例
* - 无匹配实例 回退到共享实例
* </pre>
*
* <h3>配置示例</h3>
* <pre> * <pre>
* tenant: * tenant:
* routing: * routing:
* enabled: true * enabled: true
* default-tenant-id: 1 * tenant-header: X-Tenant-Id
* services: * default-tenant-id: "1"
* fund-sys: * fallback-to-shared: true
* vip-tenants: * shared-services:
* - TENANT_VIP_001 * - fund-gateway
* fallback-to-shared: true * - fund-report
* </pre> * </pre>
*/ */
@Component @Component
@ -49,13 +61,8 @@ public class TenantRoutingProperties {
"fund-file" "fund-file"
); );
/** 租户服务配置映射 */ /** 是否回退到共享实例(当找不到租户专属实例时) */
private Map<String, TenantServiceConfig> services = new HashMap<>(); private boolean fallbackToShared = true;
/** 租户服务配置(旧版兼容) */
private Map<String, TenantServiceConfig> tenantConfigs = new HashMap<>();
// Getters and Setters
public boolean isEnabled() { public boolean isEnabled() {
return enabled; return enabled;
@ -105,24 +112,19 @@ public class TenantRoutingProperties {
this.sharedServices = sharedServices; this.sharedServices = sharedServices;
} }
public Map<String, TenantServiceConfig> getServices() { public boolean isFallbackToShared() {
return services; return fallbackToShared;
} }
public void setServices(Map<String, TenantServiceConfig> services) { public void setFallbackToShared(boolean fallbackToShared) {
this.services = services; this.fallbackToShared = fallbackToShared;
}
public Map<String, TenantServiceConfig> getTenantConfigs() {
return tenantConfigs;
}
public void setTenantConfigs(Map<String, TenantServiceConfig> tenantConfigs) {
this.tenantConfigs = tenantConfigs;
} }
/** /**
* 构建租户组名称 * 构建租户组名称
*
* @param tenantId 租户 ID
* @return 租户组名称 "TENANT_VIP_001"
*/ */
public String buildTenantGroup(String tenantId) { public String buildTenantGroup(String tenantId) {
if (tenantId == null || tenantId.isEmpty()) { if (tenantId == null || tenantId.isEmpty()) {
@ -133,205 +135,11 @@ public class TenantRoutingProperties {
/** /**
* 判断是否为共享服务 * 判断是否为共享服务
*
* @param serviceName 服务名
* @return 是否为共享服务
*/ */
public boolean isSharedService(String serviceName) { public boolean isSharedService(String serviceName) {
return sharedServices.contains(serviceName); return sharedServices != null && sharedServices.contains(serviceName);
}
/**
* 获取服务的 VIP 租户列表
*/
public List<String> 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<String> 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<String> vipTenants = new ArrayList<>();
/** 是否回退到共享实例 */
private boolean fallbackToShared = true;
/** 租户 ID */
private String tenantId;
/** 服务实例配置 */
private Map<String, ServiceInstanceConfig> instances = new HashMap<>();
/** 数据库配置(一库一租户模式) */
private DatabaseConfig database;
// Getters and Setters
public List<String> getVipTenants() {
return vipTenants;
}
public void setVipTenants(List<String> 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;
}
public void setTenantId(String tenantId) {
this.tenantId = tenantId;
}
public Map<String, ServiceInstanceConfig> getInstances() {
return instances;
}
public void setInstances(Map<String, ServiceInstanceConfig> instances) {
this.instances = instances;
}
public DatabaseConfig getDatabase() {
return database;
}
public void setDatabase(DatabaseConfig database) {
this.database = database;
}
}
/**
* 服务实例配置
*/
public static class ServiceInstanceConfig {
/** 服务名 */
private String serviceName;
/** 端口号 */
private int port = 8080;
/** 实例数(用于负载均衡) */
private int replicas = 1;
/** 权重(用于加权负载均衡) */
private int weight = 1;
// Getters and Setters
public String getServiceName() {
return serviceName;
}
public void setServiceName(String serviceName) {
this.serviceName = serviceName;
}
public int getPort() {
return port;
}
public void setPort(int port) {
this.port = port;
}
public int getReplicas() {
return replicas;
}
public void setReplicas(int replicas) {
this.replicas = replicas;
}
public int getWeight() {
return weight;
}
public void setWeight(int weight) {
this.weight = weight;
}
}
/**
* 数据库配置用于一库一租户
*/
public static class DatabaseConfig {
/** JDBC URL */
private String url;
/** 用户名 */
private String username;
/** 密码 */
private String password;
/** 驱动类名 */
private String driverClassName = "com.mysql.cj.jdbc.Driver";
// Getters and Setters
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getDriverClassName() {
return driverClassName;
}
public void setDriverClassName(String driverClassName) {
this.driverClassName = driverClassName;
}
} }
} }

View File

@ -180,7 +180,7 @@ public class TenantAwareLoadBalancer implements ReactorServiceInstanceLoadBalanc
// 检查是否启用回退到共享实例 // 检查是否启用回退到共享实例
boolean fallbackEnabled = true; boolean fallbackEnabled = true;
if (routingProperties != null) { if (routingProperties != null) {
fallbackEnabled = routingProperties.isFallbackToShared(serviceId); fallbackEnabled = routingProperties.isFallbackToShared();
} }
if (!fallbackEnabled) { if (!fallbackEnabled) {

View File

@ -1,4 +1,4 @@
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
Test set: com.fundplatform.common.loadbalancer.TenantAwareLoadBalancerTest Test set: com.fundplatform.common.loadbalancer.TenantAwareLoadBalancerTest
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
Tests run: 3, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.567 s -- in com.fundplatform.common.loadbalancer.TenantAwareLoadBalancerTest Tests run: 3, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.310 s -- in com.fundplatform.common.loadbalancer.TenantAwareLoadBalancerTest

View File

@ -128,7 +128,7 @@ logging:
org.springframework.cloud.gateway: DEBUG org.springframework.cloud.gateway: DEBUG
com.fundplatform.common.loadbalancer: DEBUG com.fundplatform.common.loadbalancer: DEBUG
# 多租户路由配置 # 多租户路由配置Gateway 全局配置)
tenant: tenant:
routing: routing:
enabled: true enabled: true
@ -136,21 +136,10 @@ tenant:
tenant-group-header: X-Tenant-Group tenant-group-header: X-Tenant-Group
group-separator: TENANT_ group-separator: TENANT_
default-tenant-id: "1" default-tenant-id: "1"
# 共享服务列表(不需要租户路由的服务)
shared-services: shared-services:
- fund-gateway - fund-gateway
- fund-report - fund-report
- fund-file - fund-file
services: # 默认回退策略
fund-sys: fallback-to-shared: true
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

View File

@ -128,7 +128,7 @@ logging:
org.springframework.cloud.gateway: DEBUG org.springframework.cloud.gateway: DEBUG
com.fundplatform.common.loadbalancer: DEBUG com.fundplatform.common.loadbalancer: DEBUG
# 多租户路由配置 # 多租户路由配置Gateway 全局配置)
tenant: tenant:
routing: routing:
enabled: true enabled: true
@ -136,21 +136,10 @@ tenant:
tenant-group-header: X-Tenant-Group tenant-group-header: X-Tenant-Group
group-separator: TENANT_ group-separator: TENANT_
default-tenant-id: "1" default-tenant-id: "1"
# 共享服务列表(不需要租户路由的服务)
shared-services: shared-services:
- fund-gateway - fund-gateway
- fund-report - fund-report
- fund-file - fund-file
services: # 默认回退策略
fund-sys: fallback-to-shared: true
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

View File

@ -76,22 +76,18 @@ logging:
pattern: pattern:
console: "%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n" console: "%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n"
# 多租户路由配置 # 多租户路由配置(服务实例只需声明自己的租户组)
tenant: tenant:
routing: routing:
enabled: true enabled: true
tenant-header: X-Tenant-Id tenant-header: X-Tenant-Id
tenant-group-header: X-Tenant-Group tenant-group-header: X-Tenant-Group
group-separator: TENANT_
default-tenant-id: "1" default-tenant-id: "1"
# 共享服务列表
shared-services: shared-services:
- fund-gateway - fund-gateway
- fund-report - fund-report
- fund-file - fund-file
services: # 回退到共享实例
fund-sys: fallback-to-shared: true
vip-tenants:
- TENANT_VIP_001
- TENANT_VIP_002
fallback-to-shared: true

View File

@ -76,22 +76,18 @@ logging:
pattern: pattern:
console: "%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n" console: "%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n"
# 多租户路由配置 # 多租户路由配置(服务实例只需声明自己的租户组)
tenant: tenant:
routing: routing:
enabled: true enabled: true
tenant-header: X-Tenant-Id tenant-header: X-Tenant-Id
tenant-group-header: X-Tenant-Group tenant-group-header: X-Tenant-Group
group-separator: TENANT_
default-tenant-id: "1" default-tenant-id: "1"
# 共享服务列表
shared-services: shared-services:
- fund-gateway - fund-gateway
- fund-report - fund-report
- fund-file - fund-file
services: # 回退到共享实例
fund-sys: fallback-to-shared: true
vip-tenants:
- TENANT_VIP_001
- TENANT_VIP_002
fallback-to-shared: true

View File

@ -1102,3 +1102,21 @@ java.lang.NullPointerException: Cannot invoke "com.zaxxer.hikari.HikariPoolMXBea
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1144) at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1144)
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:642) at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:642)
at java.base/java.lang.Thread.run(Thread.java:1583) at java.base/java.lang.Thread.run(Thread.java:1583)
2026-02-19 21:16:06.988 [scheduling-1] [] INFO com.fundplatform.sys.config.HikariMonitorConfig - === HikariCP 连接池状态 ===
2026-02-19 21:16:06.991 [scheduling-1] [] INFO com.fundplatform.sys.config.HikariMonitorConfig - 连接池名称: FundSysHikariPool
2026-02-19 21:16:06.991 [scheduling-1] [] ERROR o.s.s.support.TaskUtils$LoggingErrorHandler - Unexpected error occurred in scheduled task
java.lang.NullPointerException: Cannot invoke "com.zaxxer.hikari.HikariPoolMXBean.getActiveConnections()" because the return value of "com.zaxxer.hikari.HikariDataSource.getHikariPoolMXBean()" is null
at com.fundplatform.sys.config.HikariMonitorConfig.monitorHikariPool(HikariMonitorConfig.java:38)
at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103)
at java.base/java.lang.reflect.Method.invoke(Method.java:580)
at org.springframework.scheduling.support.ScheduledMethodRunnable.runInternal(ScheduledMethodRunnable.java:130)
at org.springframework.scheduling.support.ScheduledMethodRunnable.lambda$run$2(ScheduledMethodRunnable.java:124)
at io.micrometer.observation.Observation.observe(Observation.java:499)
at org.springframework.scheduling.support.ScheduledMethodRunnable.run(ScheduledMethodRunnable.java:124)
at org.springframework.scheduling.support.DelegatingErrorHandlingRunnable.run(DelegatingErrorHandlingRunnable.java:54)
at java.base/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:572)
at java.base/java.util.concurrent.FutureTask.runAndReset(FutureTask.java:358)
at java.base/java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:305)
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1144)
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:642)
at java.base/java.lang.Thread.run(Thread.java:1583)

View File

@ -1066,3 +1066,21 @@ java.lang.NullPointerException: Cannot invoke "com.zaxxer.hikari.HikariPoolMXBea
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1144) at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1144)
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:642) at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:642)
at java.base/java.lang.Thread.run(Thread.java:1583) at java.base/java.lang.Thread.run(Thread.java:1583)
2026-02-19 21:14:07.541 [scheduling-1] [] INFO com.fundplatform.sys.config.HikariMonitorConfig - === HikariCP 连接池状态 ===
2026-02-19 21:14:07.550 [scheduling-1] [] INFO com.fundplatform.sys.config.HikariMonitorConfig - 连接池名称: FundSysHikariPool
2026-02-19 21:14:07.551 [scheduling-1] [] ERROR o.s.s.support.TaskUtils$LoggingErrorHandler - Unexpected error occurred in scheduled task
java.lang.NullPointerException: Cannot invoke "com.zaxxer.hikari.HikariPoolMXBean.getActiveConnections()" because the return value of "com.zaxxer.hikari.HikariDataSource.getHikariPoolMXBean()" is null
at com.fundplatform.sys.config.HikariMonitorConfig.monitorHikariPool(HikariMonitorConfig.java:38)
at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103)
at java.base/java.lang.reflect.Method.invoke(Method.java:580)
at org.springframework.scheduling.support.ScheduledMethodRunnable.runInternal(ScheduledMethodRunnable.java:130)
at org.springframework.scheduling.support.ScheduledMethodRunnable.lambda$run$2(ScheduledMethodRunnable.java:124)
at io.micrometer.observation.Observation.observe(Observation.java:499)
at org.springframework.scheduling.support.ScheduledMethodRunnable.run(ScheduledMethodRunnable.java:124)
at org.springframework.scheduling.support.DelegatingErrorHandlingRunnable.run(DelegatingErrorHandlingRunnable.java:54)
at java.base/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:572)
at java.base/java.util.concurrent.FutureTask.runAndReset(FutureTask.java:358)
at java.base/java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:305)
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1144)
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:642)
at java.base/java.lang.Thread.run(Thread.java:1583)

View File

@ -1438,3 +1438,35 @@ java.lang.NullPointerException: Cannot invoke "com.zaxxer.hikari.HikariPoolMXBea
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1144) at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1144)
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:642) at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:642)
at java.base/java.lang.Thread.run(Thread.java:1583) at java.base/java.lang.Thread.run(Thread.java:1583)
2026-02-19 21:14:07.551 [scheduling-1] [] ERROR o.s.s.support.TaskUtils$LoggingErrorHandler - Unexpected error occurred in scheduled task
java.lang.NullPointerException: Cannot invoke "com.zaxxer.hikari.HikariPoolMXBean.getActiveConnections()" because the return value of "com.zaxxer.hikari.HikariDataSource.getHikariPoolMXBean()" is null
at com.fundplatform.sys.config.HikariMonitorConfig.monitorHikariPool(HikariMonitorConfig.java:38)
at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103)
at java.base/java.lang.reflect.Method.invoke(Method.java:580)
at org.springframework.scheduling.support.ScheduledMethodRunnable.runInternal(ScheduledMethodRunnable.java:130)
at org.springframework.scheduling.support.ScheduledMethodRunnable.lambda$run$2(ScheduledMethodRunnable.java:124)
at io.micrometer.observation.Observation.observe(Observation.java:499)
at org.springframework.scheduling.support.ScheduledMethodRunnable.run(ScheduledMethodRunnable.java:124)
at org.springframework.scheduling.support.DelegatingErrorHandlingRunnable.run(DelegatingErrorHandlingRunnable.java:54)
at java.base/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:572)
at java.base/java.util.concurrent.FutureTask.runAndReset(FutureTask.java:358)
at java.base/java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:305)
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1144)
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:642)
at java.base/java.lang.Thread.run(Thread.java:1583)
2026-02-19 21:16:06.991 [scheduling-1] [] ERROR o.s.s.support.TaskUtils$LoggingErrorHandler - Unexpected error occurred in scheduled task
java.lang.NullPointerException: Cannot invoke "com.zaxxer.hikari.HikariPoolMXBean.getActiveConnections()" because the return value of "com.zaxxer.hikari.HikariDataSource.getHikariPoolMXBean()" is null
at com.fundplatform.sys.config.HikariMonitorConfig.monitorHikariPool(HikariMonitorConfig.java:38)
at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103)
at java.base/java.lang.reflect.Method.invoke(Method.java:580)
at org.springframework.scheduling.support.ScheduledMethodRunnable.runInternal(ScheduledMethodRunnable.java:130)
at org.springframework.scheduling.support.ScheduledMethodRunnable.lambda$run$2(ScheduledMethodRunnable.java:124)
at io.micrometer.observation.Observation.observe(Observation.java:499)
at org.springframework.scheduling.support.ScheduledMethodRunnable.run(ScheduledMethodRunnable.java:124)
at org.springframework.scheduling.support.DelegatingErrorHandlingRunnable.run(DelegatingErrorHandlingRunnable.java:54)
at java.base/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:572)
at java.base/java.util.concurrent.FutureTask.runAndReset(FutureTask.java:358)
at java.base/java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:305)
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1144)
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:642)
at java.base/java.lang.Thread.run(Thread.java:1583)

View File

@ -324,3 +324,7 @@
2026-02-19 21:09:07.550 [scheduling-1] [] INFO com.fundplatform.sys.config.HikariMonitorConfig - 连接池名称: FundSysHikariPool 2026-02-19 21:09:07.550 [scheduling-1] [] INFO com.fundplatform.sys.config.HikariMonitorConfig - 连接池名称: FundSysHikariPool
2026-02-19 21:11:06.988 [scheduling-1] [] INFO com.fundplatform.sys.config.HikariMonitorConfig - === HikariCP 连接池状态 === 2026-02-19 21:11:06.988 [scheduling-1] [] INFO com.fundplatform.sys.config.HikariMonitorConfig - === HikariCP 连接池状态 ===
2026-02-19 21:11:06.996 [scheduling-1] [] INFO com.fundplatform.sys.config.HikariMonitorConfig - 连接池名称: FundSysHikariPool 2026-02-19 21:11:06.996 [scheduling-1] [] INFO com.fundplatform.sys.config.HikariMonitorConfig - 连接池名称: FundSysHikariPool
2026-02-19 21:14:07.541 [scheduling-1] [] INFO com.fundplatform.sys.config.HikariMonitorConfig - === HikariCP 连接池状态 ===
2026-02-19 21:14:07.550 [scheduling-1] [] INFO com.fundplatform.sys.config.HikariMonitorConfig - 连接池名称: FundSysHikariPool
2026-02-19 21:16:06.988 [scheduling-1] [] INFO com.fundplatform.sys.config.HikariMonitorConfig - === HikariCP 连接池状态 ===
2026-02-19 21:16:06.991 [scheduling-1] [] INFO com.fundplatform.sys.config.HikariMonitorConfig - 连接池名称: FundSysHikariPool