SpringBoot+Hikari多数据源配置

 

 

 目录结构:

 

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.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import java.lang.reflect.Method;
import java.util.Objects;
/**
 * @Description 动态数据源AOP切换
 * @Author WangKun
 * @Date 2023/4/4 11:23
 * @Version
 */
@Aspect
@Component
@Order(1) //配置加载顺序
public class DataSourceAspect {
    @Pointcut("@annotation(DB类的路径)")
    public void doPointCut() {
    }
    /**
     * @param point
     * @Description 切点
     * @Throws
     * @Return java.lang.Object
     * @Date 2023-04-04 11:24:11
     * @Author WangKun
     */
    @Around("doPointCut()")
    public Object around(ProceedingJoinPoint point) throws Throwable {
        DB dataSource = getDataSource(point);
        if (!Objects.isNull(dataSource)) {
            DynamicDataSourceContextHolder.setDataSourceType(dataSource.value().name());
        }
        try {
            return point.proceed();
        } finally {
            // 在执行方法之后 销毁数据源
            DynamicDataSourceContextHolder.clearDataSourceType();
        }
    }
    /**
     * @param point
     * @Description 获取@DB注解
     * @Throws
     * @Return com.harmonywisdom.common.system.annotation.DB
     * @Date 2023-04-04 11:25:03
     * @Author WangKun
     */
    public DB getDataSource(ProceedingJoinPoint point) {
        //获得当前访问的class
        Class className = point.getTarget().getClass();
        // 判断是否存在@DateBase注解
        if (className.isAnnotationPresent(DB.class)) {
            //获取注解
            return className.getAnnotation(DB.class);
        }
        Method method = ((MethodSignature) point.getSignature()).getMethod();
        return method.getAnnotation(DB.class);
    }
}
import java.lang.annotation.*;
/**
 * @Description 注解方式切换 在**ServiceImpl中的方法上面使用此注解,默认位主数据库可不写,  @DB(DataSourceType.DB2)
 * @Author WangKun
 * @Date 2023/4/4 14:23
 * @Version
 */
@Target({ ElementType.METHOD, ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
public @interface DB
{
    /**
     * 切换数据源名称
     */
     DataSourceType value() default DataSourceType.DB1;
}
\
import com.zaxxer.hikari.HikariDataSource;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.jdbc.DataSourceBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import javax.sql.DataSource;
import java.util.HashMap;
import java.util.Map;
/**
 * @Description Hikari多数据源配置
 * @Author WangKun
 * @Date 2023/4/4 15:00
 * @Version
 */
@Configuration
public class HikariConfig {
    @Bean(name = "dataSourceDb1")
    @ConfigurationProperties("spring.datasource.db1")
    public DataSource dataSourceDb1(HikariProperties properties) {
        HikariDataSource dataSource = DataSourceBuilder.create().type(HikariDataSource.class).build();
        return properties.dataSource(dataSource);
    }
    @Bean(name = "dataSourceDb2")
    @ConfigurationProperties("spring.datasource.db2")
    public DataSource dataSourceDb2(HikariProperties properties) {
        HikariDataSource dataSource = DataSourceBuilder.create().type(HikariDataSource.class).build();
        return properties.dataSource(dataSource);
    }
    @Bean(name = "dataSourceDb3")
    @ConfigurationProperties("spring.datasource.db3")
    public DataSource dataSourceDb3(HikariProperties properties) {
        HikariDataSource dataSource = DataSourceBuilder.create().type(HikariDataSource.class).build();
        return properties.dataSource(dataSource);
    }
    @Bean(name = "dataSourceDb4")
    @ConfigurationProperties("spring.datasource.db4")
    public DataSource dataSourceDb4(HikariProperties properties) {
        HikariDataSource dataSource = DataSourceBuilder.create().type(HikariDataSource.class).build();
        return properties.dataSource(dataSource);
    }
    @Primary
    @Bean(name = "dynamicDataSource")
    public DynamicDataSource dataSource(DataSource dataSourceDb1, DataSource dataSourceDb2, DataSource dataSourceDb3, DataSource dataSourceDb4) {
        Map targetDataSources = new HashMap<>();
        targetDataSources.put(DataSourceType.DB1.name(), dataSourceDb1);
        targetDataSources.put(DataSourceType.DB2.name(), dataSourceDb2);
        targetDataSources.put(DataSourceType.DB3.name(), dataSourceDb3);
        targetDataSources.put(DataSourceType.DB4.name(), dataSourceDb4);
        return new DynamicDataSource(dataSourceDb1, targetDataSources);
    }
    /**
     * @param dataSource
     * @Description 创建事务
     * @Throws
     * @Return org.springframework.jdbc.datasource.DataSourceTransactionManager
     * @Date 2023-04-10 15:26:50
     * @Author WangKun
     */
    @Primary
    @Bean(name = "transactionManager")
    public DataSourceTransactionManager transactionManager(@Qualifier("dynamicDataSource") DataSource dataSource) {
        return new DataSourceTransactionManager(dataSource);
    }
}
import com.zaxxer.hikari.HikariDataSource;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
/**
 * @Description Hikari连接池设置
 * @Author WangKun
 * @Date 2023/4/4 15:05
 * @Version
 */
@Configuration
public class HikariProperties {
    @Value("${spring.datasource.hikari.minimumIdle}")
    private int minIdle;
    @Value("${spring.datasource.hikari.maximumPoolSize}")
    private int maxPoolSize;
    @Value("${spring.datasource.hikari.idleTimeout}")
    private int idleTimeout;
    @Value("${spring.datasource.hikari.maxLifetime}")
    private int maxLifetime;
    @Value("${spring.datasource.hikari.connectionTimeout}")
    private int connectionTimeout;
    public HikariDataSource dataSource(HikariDataSource dataSource) {
        //配置Hikari连接池
        dataSource.setConnectionTimeout(connectionTimeout);//连接超时时间设置
        dataSource.setIdleTimeout(idleTimeout);//连接空闲生命周期设置
        dataSource.setMaximumPoolSize(maxPoolSize);//连接池允许的最大连接数量
        dataSource.setMaxLifetime(maxLifetime);//检查空余连接优化连接池设置时间,单位毫秒
        dataSource.setMinimumIdle(minIdle);//连接池保持最小空余连接数量
        return dataSource;
    }
}
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
import javax.sql.DataSource;
import java.util.Map;
/**
 * @Description 自定义动态数据源
 * @Author WangKun
 * @Date 2023/4/4 15:05
 * @Version
 */
public class DynamicDataSource extends AbstractRoutingDataSource {
    public DynamicDataSource(DataSource defaultTargetDataSource, Map targetDataSources) {
        super.setDefaultTargetDataSource(defaultTargetDataSource);
        super.setTargetDataSources(targetDataSources);
        super.afterPropertiesSet();
    }
    @Override
    protected Object determineCurrentLookupKey() {
        return DynamicDataSourceContextHolder.getDataSourceType();
    }
}
import lombok.extern.slf4j.Slf4j;
/**
 * @Description 动态数据源切换处理
 * @Author WangKun
 * @Date 2023/4/4 11:30
 * @Version
 */
@Slf4j
public class DynamicDataSourceContextHolder {
    /**
     * 使用ThreadLocal维护变量,ThreadLocal为每个使用该变量的线程提供独立的变量,
     * 所以每一个线程都可以独立地改变自己,而不会影响其它线程。
     */
    private static final ThreadLocal CONTEXT_HOLDER = new ThreadLocal<>();
    /**
     * @param dsType
     * @Description 设置数据源的变量
     * @Throws
     * @Return void
     * @Date 2023-04-04 11:30:21
     * @Author WangKun
     */
    public static void setDataSourceType(String dsType) {
        CONTEXT_HOLDER.set(dsType);
        log.info("连接到{}数据源", dsType);
    }
    /**
     * @param
     * @Description 获得数据源的变量
     * @Throws
     * @Return java.lang.String
     * @Date 2023-04-04 11:30:45
     * @Author WangKun
     */
    public static String getDataSourceType() {
        return CONTEXT_HOLDER.get();
    }
    /**
     * @param
     * @Description 清空数据源变量
     * @Throws
     * @Return void
     * @Date 2023-04-04 11:30:51
     * @Author WangKun
     */
    public static void clearDataSourceType() {
        CONTEXT_HOLDER.remove();
    }
}
/**
 * @Description 数据源枚举
 * @Author WangKun
 * @Date 2023/4/4 11:23
 * @Version
 */
public enum DataSourceType {
    /**数据源1 */
    DB1,
    /**数据源2 */
    DB2,
    /**数据源3 */
    DB3,
    /**数据源4 */
    DB4
}

调用: