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:
parent
2765f3f265
commit
330ec6dea9
@ -3,24 +3,36 @@ package com.fundplatform.common.config;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
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>
|
||||
* tenant:
|
||||
* routing:
|
||||
* enabled: true
|
||||
* default-tenant-id: 1
|
||||
* services:
|
||||
* fund-sys:
|
||||
* vip-tenants:
|
||||
* - TENANT_VIP_001
|
||||
* fallback-to-shared: true
|
||||
* tenant-header: X-Tenant-Id
|
||||
* default-tenant-id: "1"
|
||||
* fallback-to-shared: true
|
||||
* shared-services:
|
||||
* - fund-gateway
|
||||
* - fund-report
|
||||
* </pre>
|
||||
*/
|
||||
@Component
|
||||
@ -49,13 +61,8 @@ public class TenantRoutingProperties {
|
||||
"fund-file"
|
||||
);
|
||||
|
||||
/** 租户服务配置映射 */
|
||||
private Map<String, TenantServiceConfig> services = new HashMap<>();
|
||||
|
||||
/** 租户服务配置(旧版兼容) */
|
||||
private Map<String, TenantServiceConfig> tenantConfigs = new HashMap<>();
|
||||
|
||||
// Getters and Setters
|
||||
/** 是否回退到共享实例(当找不到租户专属实例时) */
|
||||
private boolean fallbackToShared = true;
|
||||
|
||||
public boolean isEnabled() {
|
||||
return enabled;
|
||||
@ -105,24 +112,19 @@ public class TenantRoutingProperties {
|
||||
this.sharedServices = sharedServices;
|
||||
}
|
||||
|
||||
public Map<String, TenantServiceConfig> getServices() {
|
||||
return services;
|
||||
public boolean isFallbackToShared() {
|
||||
return fallbackToShared;
|
||||
}
|
||||
|
||||
public void setServices(Map<String, TenantServiceConfig> services) {
|
||||
this.services = services;
|
||||
}
|
||||
|
||||
public Map<String, TenantServiceConfig> getTenantConfigs() {
|
||||
return tenantConfigs;
|
||||
}
|
||||
|
||||
public void setTenantConfigs(Map<String, TenantServiceConfig> tenantConfigs) {
|
||||
this.tenantConfigs = tenantConfigs;
|
||||
public void setFallbackToShared(boolean fallbackToShared) {
|
||||
this.fallbackToShared = fallbackToShared;
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建租户组名称
|
||||
*
|
||||
* @param tenantId 租户 ID
|
||||
* @return 租户组名称,如 "TENANT_VIP_001"
|
||||
*/
|
||||
public String buildTenantGroup(String tenantId) {
|
||||
if (tenantId == null || tenantId.isEmpty()) {
|
||||
@ -133,205 +135,11 @@ public class TenantRoutingProperties {
|
||||
|
||||
/**
|
||||
* 判断是否为共享服务
|
||||
*
|
||||
* @param serviceName 服务名
|
||||
* @return 是否为共享服务
|
||||
*/
|
||||
public boolean isSharedService(String serviceName) {
|
||||
return 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;
|
||||
}
|
||||
return sharedServices != null && sharedServices.contains(serviceName);
|
||||
}
|
||||
}
|
||||
|
||||
@ -180,7 +180,7 @@ public class TenantAwareLoadBalancer implements ReactorServiceInstanceLoadBalanc
|
||||
// 检查是否启用回退到共享实例
|
||||
boolean fallbackEnabled = true;
|
||||
if (routingProperties != null) {
|
||||
fallbackEnabled = routingProperties.isFallbackToShared(serviceId);
|
||||
fallbackEnabled = routingProperties.isFallbackToShared();
|
||||
}
|
||||
|
||||
if (!fallbackEnabled) {
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
File diff suppressed because one or more lines are too long
@ -1,4 +1,4 @@
|
||||
-------------------------------------------------------------------------------
|
||||
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
|
||||
|
||||
@ -128,7 +128,7 @@ logging:
|
||||
org.springframework.cloud.gateway: DEBUG
|
||||
com.fundplatform.common.loadbalancer: DEBUG
|
||||
|
||||
# 多租户路由配置
|
||||
# 多租户路由配置(Gateway 全局配置)
|
||||
tenant:
|
||||
routing:
|
||||
enabled: true
|
||||
@ -136,21 +136,10 @@ tenant:
|
||||
tenant-group-header: X-Tenant-Group
|
||||
group-separator: TENANT_
|
||||
default-tenant-id: "1"
|
||||
# 共享服务列表(不需要租户路由的服务)
|
||||
shared-services:
|
||||
- fund-gateway
|
||||
- fund-report
|
||||
- fund-file
|
||||
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
|
||||
# 默认回退策略
|
||||
fallback-to-shared: true
|
||||
|
||||
@ -128,7 +128,7 @@ logging:
|
||||
org.springframework.cloud.gateway: DEBUG
|
||||
com.fundplatform.common.loadbalancer: DEBUG
|
||||
|
||||
# 多租户路由配置
|
||||
# 多租户路由配置(Gateway 全局配置)
|
||||
tenant:
|
||||
routing:
|
||||
enabled: true
|
||||
@ -136,21 +136,10 @@ tenant:
|
||||
tenant-group-header: X-Tenant-Group
|
||||
group-separator: TENANT_
|
||||
default-tenant-id: "1"
|
||||
# 共享服务列表(不需要租户路由的服务)
|
||||
shared-services:
|
||||
- fund-gateway
|
||||
- fund-report
|
||||
- fund-file
|
||||
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
|
||||
# 默认回退策略
|
||||
fallback-to-shared: true
|
||||
|
||||
@ -76,22 +76,18 @@ logging:
|
||||
pattern:
|
||||
console: "%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n"
|
||||
|
||||
# 多租户路由配置
|
||||
# 多租户路由配置(服务实例只需声明自己的租户组)
|
||||
tenant:
|
||||
routing:
|
||||
enabled: true
|
||||
tenant-header: X-Tenant-Id
|
||||
tenant-group-header: X-Tenant-Group
|
||||
group-separator: TENANT_
|
||||
default-tenant-id: "1"
|
||||
# 共享服务列表
|
||||
shared-services:
|
||||
- fund-gateway
|
||||
- fund-report
|
||||
- fund-file
|
||||
services:
|
||||
fund-sys:
|
||||
vip-tenants:
|
||||
- TENANT_VIP_001
|
||||
- TENANT_VIP_002
|
||||
fallback-to-shared: true
|
||||
# 回退到共享实例
|
||||
fallback-to-shared: true
|
||||
|
||||
|
||||
@ -76,22 +76,18 @@ logging:
|
||||
pattern:
|
||||
console: "%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n"
|
||||
|
||||
# 多租户路由配置
|
||||
# 多租户路由配置(服务实例只需声明自己的租户组)
|
||||
tenant:
|
||||
routing:
|
||||
enabled: true
|
||||
tenant-header: X-Tenant-Id
|
||||
tenant-group-header: X-Tenant-Group
|
||||
group-separator: TENANT_
|
||||
default-tenant-id: "1"
|
||||
# 共享服务列表
|
||||
shared-services:
|
||||
- fund-gateway
|
||||
- fund-report
|
||||
- fund-file
|
||||
services:
|
||||
fund-sys:
|
||||
vip-tenants:
|
||||
- TENANT_VIP_001
|
||||
- TENANT_VIP_002
|
||||
fallback-to-shared: true
|
||||
# 回退到共享实例
|
||||
fallback-to-shared: true
|
||||
|
||||
|
||||
@ -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$Worker.run(ThreadPoolExecutor.java:642)
|
||||
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)
|
||||
|
||||
@ -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$Worker.run(ThreadPoolExecutor.java:642)
|
||||
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)
|
||||
|
||||
@ -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$Worker.run(ThreadPoolExecutor.java:642)
|
||||
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)
|
||||
|
||||
@ -324,3 +324,7 @@
|
||||
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.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
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user