From 152781b05131e48bf6e94d71cc72dd54af52a3fb Mon Sep 17 00:00:00 2001 From: houzhongjian <houzhongyi@126.com> Date: 星期四, 10 四月 2025 14:13:29 +0800 Subject: [PATCH] 恢复iailab-framework --- iailab-framework/iailab-common-biz-tenant/src/main/java/com/iailab/framework/tenant/core/db/dynamic/TenantDsProcessor.java | 106 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 106 insertions(+), 0 deletions(-) diff --git a/iailab-framework/iailab-common-biz-tenant/src/main/java/com/iailab/framework/tenant/core/db/dynamic/TenantDsProcessor.java b/iailab-framework/iailab-common-biz-tenant/src/main/java/com/iailab/framework/tenant/core/db/dynamic/TenantDsProcessor.java new file mode 100644 index 0000000..24b2eff --- /dev/null +++ b/iailab-framework/iailab-common-biz-tenant/src/main/java/com/iailab/framework/tenant/core/db/dynamic/TenantDsProcessor.java @@ -0,0 +1,106 @@ +package com.iailab.framework.tenant.core.db.dynamic; + +import com.baomidou.dynamic.datasource.DynamicRoutingDataSource; +import com.baomidou.dynamic.datasource.creator.DataSourceProperty; +import com.baomidou.dynamic.datasource.creator.DefaultDataSourceCreator; +import com.baomidou.dynamic.datasource.processor.DsProcessor; +import com.iailab.framework.tenant.core.context.DataContextHolder; +import com.iailab.framework.tenant.core.context.TenantContextHolder; +import com.iailab.framework.tenant.core.service.TenantFrameworkService; +import com.iailab.module.infra.api.db.DataSourceConfigServiceApi; +import com.iailab.module.infra.api.db.dto.DataSourceConfigRespDTO; +import lombok.RequiredArgsConstructor; +import org.aopalliance.intercept.MethodInvocation; +import org.springframework.context.annotation.Lazy; + +import javax.annotation.Resource; +import javax.sql.DataSource; +import java.util.Objects; + +/** + * 基于 {@link TenantDS} 的数据源处理器 + * + * 1. 如果有 @TenantDS 注解,返回该租户的数据源 + * 2. 如果该租户的数据源未创建,则进行创建 + * + * @author 芋道源码 + */ +@RequiredArgsConstructor +public class TenantDsProcessor extends DsProcessor { + + /** + * 用于获取租户数据源配置的 Service + */ + @Resource + @Lazy + private TenantFrameworkService tenantFrameworkService; + + /** + * 动态数据源 + */ + @Resource + @Lazy // 为什么添加 @Lazy 注解?因为它和 DynamicRoutingDataSource 相互依赖,导致无法初始化 + private DynamicRoutingDataSource dynamicRoutingDataSource; + + /** + * 用于创建租户数据源的 Creator + */ + @Resource + @Lazy + private DefaultDataSourceCreator dataSourceCreator; + + @Resource + @Lazy + private DataSourceConfigServiceApi dataSourceConfigServiceApi; + + @Override + public boolean matches(String key) { + return Objects.equals(key, TenantDS.KEY) || Objects.equals(key, DataDS.KEY); + } + + @Override + public String doDetermineDatasource(MethodInvocation invocation, String key) { + if (DataDS.KEY.equals(key)){ + // 获得数据源配置 + Long dataSourceId = DataContextHolder.getRequiredDataSourceId(); + DataSourceConfigRespDTO dataSourceConfigRespDTO = dataSourceConfigServiceApi.getDataSourceConfig(dataSourceId); + DataSourceProperty dataSourceProperty = new DataSourceProperty(); + dataSourceProperty.setPoolName(dataSourceConfigRespDTO.getName()); + dataSourceProperty.setUrl(dataSourceConfigRespDTO.getUrl()); + dataSourceProperty.setUsername(dataSourceConfigRespDTO.getUsername()); + dataSourceProperty.setPassword(dataSourceConfigRespDTO.getPassword()); + // 创建 or 创建数据源,并返回数据源名字 + return createDatasourceIfAbsent(dataSourceProperty); + }else if(TenantDS.KEY.equals(key)){ + // 获得数据源配置 + Long tenantId = TenantContextHolder.getRequiredTenantId(); + DataSourceProperty dataSourceProperty = tenantFrameworkService.getDataSourceProperty(tenantId); + // 创建 or 创建数据源,并返回数据源名字 + return createDatasourceIfAbsent(dataSourceProperty); + } + return key; + } + + private String createDatasourceIfAbsent(DataSourceProperty dataSourceProperty) { + // 1. 重点:如果数据源不存在,则进行创建 + if (isDataSourceNotExist(dataSourceProperty)) { + // 问题一:为什么要加锁?因为,如果多个线程同时执行到这里,会导致多次创建数据源 + // 问题二:为什么要使用 poolName 加锁?保证多个不同的 poolName 可以并发创建数据源 + // 问题三:为什么要使用 intern 方法?因为,intern 方法,会返回一个字符串的常量池中的引用 + // intern 的说明,可见 https://www.cnblogs.com/xrq730/p/6662232.html 文章 + synchronized (dataSourceProperty.getPoolName().intern()) { + if (isDataSourceNotExist(dataSourceProperty)) { + DataSource dataSource = dataSourceCreator.createDataSource(dataSourceProperty); + dynamicRoutingDataSource.addDataSource(dataSourceProperty.getPoolName(), dataSource); + } + } + } + // 2. 返回数据源的名字 + return dataSourceProperty.getPoolName(); + } + + private boolean isDataSourceNotExist(DataSourceProperty dataSourceProperty) { + return !dynamicRoutingDataSource.getDataSources().containsKey(dataSourceProperty.getPoolName()); + } + +} -- Gitblit v1.9.3