|
|
@@ -1,180 +0,0 @@
|
|
|
-package com.fs.framework.aspectj;
|
|
|
-
|
|
|
-import com.alibaba.druid.pool.DruidDataSource;
|
|
|
-import com.fs.common.annotation.TenantDataScope;
|
|
|
-import com.fs.common.core.redis.RedisCacheT;
|
|
|
-import com.fs.common.enums.TenantIdType;
|
|
|
-import com.fs.common.exception.CustomException;
|
|
|
-import com.fs.common.utils.StringUtils;
|
|
|
-import com.fs.framework.datasource.DynamicDataSource;
|
|
|
-import com.fs.framework.datasource.DynamicDataSourceContextHolder;
|
|
|
-import com.fs.huifuPay.sdk.opps.core.exception.BasePayException;
|
|
|
-import com.fs.tenant.domain.TenantInfo;
|
|
|
-import com.fs.tenant.mapper.TenantInfoMapper;
|
|
|
-import lombok.extern.slf4j.Slf4j;
|
|
|
-import org.aspectj.lang.ProceedingJoinPoint;
|
|
|
-import org.aspectj.lang.annotation.Around;
|
|
|
-import org.aspectj.lang.annotation.Aspect;
|
|
|
-import org.aspectj.lang.annotation.Pointcut;
|
|
|
-import org.aspectj.lang.reflect.MethodSignature;
|
|
|
-import org.slf4j.Logger;
|
|
|
-import org.slf4j.LoggerFactory;
|
|
|
-import org.springframework.aop.aspectj.MethodInvocationProceedingJoinPoint;
|
|
|
-import org.springframework.beans.factory.annotation.Autowired;
|
|
|
-import org.springframework.beans.factory.annotation.Value;
|
|
|
-import org.springframework.core.annotation.AnnotationUtils;
|
|
|
-import org.springframework.core.annotation.Order;
|
|
|
-import org.springframework.stereotype.Component;
|
|
|
-
|
|
|
-import javax.annotation.Resource;
|
|
|
-import javax.sql.DataSource;
|
|
|
-import java.lang.reflect.Field;
|
|
|
-import java.lang.reflect.Method;
|
|
|
-import java.util.Map;
|
|
|
-import java.util.Objects;
|
|
|
-import java.util.concurrent.ConcurrentHashMap;
|
|
|
-
|
|
|
-/**
|
|
|
- * 多数据源处理
|
|
|
- *
|
|
|
- */
|
|
|
-@Slf4j
|
|
|
-@Aspect
|
|
|
-@Order(1)
|
|
|
-@Component
|
|
|
-public class TenantDataSourceAspect {
|
|
|
- private static final String TENANT_KEY = "tenant:info:";
|
|
|
- @Resource
|
|
|
- private DynamicDataSource dynamicDataSource;
|
|
|
- @Value("${tenant-id}")
|
|
|
- private Long ymlTenantId;
|
|
|
- @Autowired
|
|
|
- private TenantInfoMapper tenantInfoMapper;
|
|
|
- @Autowired
|
|
|
- private RedisCacheT<TenantInfo> redis;
|
|
|
- /**
|
|
|
- * 租户数据源缓存
|
|
|
- */
|
|
|
- private static final Map<String, DataSource> TENANT_DS_CACHE = new ConcurrentHashMap<>();
|
|
|
-
|
|
|
- @Pointcut("@annotation(com.fs.common.annotation.TenantDataScope)"
|
|
|
- + "|| @within(com.fs.common.annotation.TenantDataScope)")
|
|
|
- public void dsPointCut() {
|
|
|
-
|
|
|
- }
|
|
|
-
|
|
|
- @Around("dsPointCut()")
|
|
|
- public Object around(ProceedingJoinPoint point) throws Throwable {
|
|
|
- MethodSignature signature = (MethodSignature) point.getSignature();
|
|
|
- Method targetMethod = signature.getMethod(); // 拿到目标方法对象
|
|
|
- log.info("执行方法:{}", targetMethod.getName());
|
|
|
- TenantDataScope dataSource = getDataSource(point);
|
|
|
- TenantIdType type = dataSource.type();
|
|
|
- Long tenantId = 0L;
|
|
|
- if(type.equals(TenantIdType.YML)){
|
|
|
- tenantId = ymlTenantId;
|
|
|
- }
|
|
|
- if(type.equals(TenantIdType.REQUEST)){
|
|
|
-
|
|
|
- }
|
|
|
- switchTenant(tenantId);
|
|
|
- try {
|
|
|
- return point.proceed();
|
|
|
- } finally {
|
|
|
- // 销毁数据源 在执行方法之后
|
|
|
- DynamicDataSourceContextHolder.clearDataSourceType();
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- public void switchTenant(Long id) {
|
|
|
- TenantInfo tenantInfo = redis.getCacheObject(TENANT_KEY + id);
|
|
|
- if(tenantInfo == null){
|
|
|
- tenantInfo = tenantInfoMapper.selectById(id);
|
|
|
- if(tenantInfo == null){
|
|
|
- throw new CustomException("租户不存在请检查");
|
|
|
- }
|
|
|
- redis.setCacheObject(TENANT_KEY + id, tenantInfo);
|
|
|
- }
|
|
|
- // 用租户主键作为唯一标识
|
|
|
- String tenantKey = buildTenantKey(tenantInfo.getId());
|
|
|
-
|
|
|
- if (!TENANT_DS_CACHE.containsKey(tenantKey)) {
|
|
|
- synchronized (this) {
|
|
|
- if (!TENANT_DS_CACHE.containsKey(tenantKey)) {
|
|
|
-
|
|
|
- javax.sql.DataSource tenantDs = createTenantDataSource(tenantInfo);
|
|
|
- TENANT_DS_CACHE.put(tenantKey, tenantDs);
|
|
|
-
|
|
|
- // 动态追加到已解析的数据源
|
|
|
- Map<Object, DataSource> resolvedMap = getResolvedDataSources();
|
|
|
- resolvedMap.put(tenantKey, tenantDs);
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- // ThreadLocal 切库
|
|
|
- DynamicDataSourceContextHolder.setDataSourceType(tenantKey);
|
|
|
- }
|
|
|
-
|
|
|
- private String buildTenantKey(Long tenantId) {
|
|
|
- return "tenant:" + tenantId;
|
|
|
- }
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
- /**
|
|
|
- * 清理 ThreadLocal
|
|
|
- */
|
|
|
- public void clear() {
|
|
|
- DynamicDataSourceContextHolder.clearDataSourceType();
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * 创建租户数据源(MySQL + Druid)
|
|
|
- */
|
|
|
- private DataSource createTenantDataSource(TenantInfo tenant) {
|
|
|
-
|
|
|
- DruidDataSource ds = new DruidDataSource();
|
|
|
- ds.setUrl(tenant.getDbUrl());
|
|
|
- ds.setUsername(tenant.getDbAccount());
|
|
|
- ds.setPassword(tenant.getDbPwd());
|
|
|
-
|
|
|
- // 统一 MySQL
|
|
|
- ds.setDriverClassName("com.mysql.cj.jdbc.Driver");
|
|
|
-
|
|
|
- ds.setInitialSize(5);
|
|
|
- ds.setMinIdle(10);
|
|
|
- ds.setMaxActive(20);
|
|
|
- ds.setMaxWait(60000);
|
|
|
-
|
|
|
- return ds;
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * 反射获取 AbstractRoutingDataSource.resolvedDataSources
|
|
|
- */
|
|
|
- @SuppressWarnings("unchecked")
|
|
|
- private Map<Object, DataSource> getResolvedDataSources() {
|
|
|
- try {
|
|
|
- Field field = org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource
|
|
|
- .class.getDeclaredField("resolvedDataSources");
|
|
|
- field.setAccessible(true);
|
|
|
- return (Map<Object, DataSource>) field.get(dynamicDataSource);
|
|
|
- } catch (Exception e) {
|
|
|
- throw new IllegalStateException("获取 resolvedDataSources 失败", e);
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * 获取需要切换的数据源
|
|
|
- */
|
|
|
- public TenantDataScope getDataSource(ProceedingJoinPoint point) {
|
|
|
- MethodSignature signature = (MethodSignature) point.getSignature();
|
|
|
- TenantDataScope dataSource = AnnotationUtils.findAnnotation(signature.getMethod(), TenantDataScope.class);
|
|
|
- if (Objects.nonNull(dataSource)) {
|
|
|
- return dataSource;
|
|
|
- }
|
|
|
-
|
|
|
- return AnnotationUtils.findAnnotation(signature.getDeclaringType(), TenantDataScope.class);
|
|
|
- }
|
|
|
-}
|