springboot動態數據源切換(多數據源配置)

動態數據源切換即多數據源切換,由於業務的需要或者歷史的遺留等原因,一個項目中配置了多個數據庫,用於查詢不同類型的數據,因此我們就需要經常在各個庫中切換數據源,接下來我們將進行具體的說明:

項目結構如下:

相關類說明:

DynamicDataSource:動態獲取數據源的實現,繼承AbstractRoutingDataSource(每執行一次數據庫,動態獲取DataSource)

DynamicDataSourceContextHolder:動態數據源上下文管理,相當於在容器中管理數據源實例

DynamicDattaSourceAspect:動態數據源通知

TargetDataSource:數據源註解,作用於類、接口或者方法上,用於指定數據源

DynamicDatasourceConfig:動態數據源配置,實例化所有配置數據源

 

具體類實現:

DynamicDataSource


public class DynamicDataSource extends AbstractRoutingDataSource {
    @Override
    protected Object determineCurrentLookupKey() {
        return DynamicDataSourceContextHolder.getDataSourceType();
    }
}

DynamicDataSourceContextHolder:

    /**
     * 存放當前線程使用的數據源類型信息
     */
    private static final ThreadLocal<String> contextHolder = new ThreadLocal<String>();
    /**
     * 存放數據源id,即數據源實例名稱
     */
    public static List<String> dataSourceIds = new ArrayList<String>();

    /**
     * 設置數據源
     *
     * @param dataSourceType
     */
    public static void setDataSourceType(String dataSourceType) {
        logger.info("添加數據源實例到管理器中,dataSourceType{}", dataSourceType);
        contextHolder.set(dataSourceType);
    }

    /**
     * 獲取數據源
     *
     * @return
     */
    public static String getDataSourceType() {
        logger.info("從數據源實例管理器中獲取當前實例");
        return contextHolder.get();
    }

    /**
     * 清除數據源
     */
    public static void clearDataSourceType() {
        logger.info("清除當前數據源實例");
        contextHolder.remove();
    }

    /**
     * 判斷當前數據源是否存在
     *
     * @param dataSourceId
     * @return
     */
    public static boolean isContainsDataSource(String dataSourceId) {
        logger.info("判斷當前數據源是否存在,dataSourceId={}", dataSourceId);
        return dataSourceIds.contains(dataSourceId);
    }

DynamicDattaSourceAspect

package com.xiaofeng.datasource2.aspect;

import com.xiaofeng.datasource2.aspect.annotation.TargetDataSource;
import com.xiaofeng.datasource2.dynamic.DynamicDataSourceContextHolder;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

/**
 * @author xiaofeng
 * @version V1.0
 * @title: DynamicDattaSourceAspect
 * @package: com.xiaofeng.sys.dynamic
 * @description: 動態數據源通知
 * @date 2019/8/28 16:48
 */
@Aspect
@Order(-1)
@Component
public class DynamicDattaSourceAspect {

    private Logger logger = LoggerFactory.getLogger(DynamicDattaSourceAspect.class);

    /**
     * 改變數據源,判斷使用註解中的數據源實例名稱,根據實例名稱從上下文管理器中獲取數據源
     *
     * @param joinPoint
     * @param targetDataSource
     */
    @Before("@annotation(targetDataSource)")
    public void changeDataSource(JoinPoint joinPoint, TargetDataSource targetDataSource) {
        logger.info("選擇數據源---" + targetDataSource.value().getValue());
        DynamicDataSourceContextHolder.setDataSourceType(targetDataSource.value().getValue());
    }

    /**
     * 使用完後清理數據源
     *
     * @param joinPoint
     * @param targetDataSource
     */
    @After("@annotation(targetDataSource)")
    public void clearDataSource(JoinPoint joinPoint, TargetDataSource targetDataSource) {
        logger.debug("清除數據源 " + targetDataSource.value().getValue() + " !");
        DynamicDataSourceContextHolder.clearDataSourceType();
    }
}

TargetDataSource


@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface TargetDataSource {

    DataSourceEnum value() default DataSourceEnum.MASTER;
}

 

DynamicDatasourceConfig

 @Bean(name = "master")
    @ConfigurationProperties(prefix = "spring.datasource.druid.master")
    public DataSource master() {
        return DruidDataSourceBuilder.create().build();
    }

    @Bean(name = "slave")
    @ConfigurationProperties(prefix = "spring.datasource.druid.slave")
    public DataSource slave() {
        return DruidDataSourceBuilder.create().build();
    }

    /**
     * 動態數據源配置
     *
     * @return
     */
    @Bean
    @Primary
    public DataSource multipleDataSource(@Qualifier("master") DataSource master, @Qualifier("slave") DataSource slave) {
        DynamicDataSource multipleDataSource = new DynamicDataSource();
        Map<Object, Object> targetDataSources = new HashMap<>();
        targetDataSources.put(DataSourceEnum.MASTER.getValue(), master);
        targetDataSources.put(DataSourceEnum.SLAVE.getValue(), slave);
        //添加數據源
        multipleDataSource.setTargetDataSources(targetDataSources);
        //設置默認數據源
        multipleDataSource.setDefaultTargetDataSource(master);
        return multipleDataSource;
    }

測試類如下:

實現效果如下:

至此我們的多數據源配置(主從數據源)已完成,此種方式已經過親測驗證!

可運行完整源碼下載地址http://zyshare.cn/resource/detail/10

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章