SpringBoot運行時動態添加數據源


此方案適用於解決springboot項目運行時動態添加數據源,非靜態切換多數據源!!!

一、多數據源應用場景:

1.配置文件配置多數據源,如默認數據源:master,數據源1:salve1...,運行時動態切換已配置的數據源(master、salve1互相切換),無法在運行時動態添加配置文件中未配置的數據源。

2.配置一個默認數據源,運行時動態添加新數據源使用(本博客適用於此場景)

二、解決方案:

Spring提供了AbstractRoutingDataSource用於動態路由數據源,第一種場景繼承AbstractRoutingDataSource類並覆寫其protected abstract Object determineCurrentLookupKey()即可;
而第二種場景我們直接覆寫protected DataSource determineTargetDataSource方法即可。原理可看下AbstractRoutingDataSource對應源碼,比較簡單,不做贅述。
直接上干貨:

import com.yaoshun.util.spring.SpringUtils;
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * <p>使用步驟:</p>
 * <blockquote><pre>
 *     DynamicDataSource.dataSourcesMap.put(dataSourceKey, druidDataSource);
 *     DynamicDataSource.setDataSource(dataSourceKey);
 *     調用業務代碼</i>
 *     DynamicDataSource.clear();
 * </pre></blockquote>
 *
 */
public class DynamicDataSource extends AbstractRoutingDataSource {

    private static final ThreadLocal<String> dataSourceKey = ThreadLocal.withInitial(() -> "defaultDataSource");

    public static Map<Object, Object> dataSourcesMap = new ConcurrentHashMap<>(10);

    static {
        dataSourcesMap.put("defaultDataSource", SpringUtils.getBean("defaultDataSource"));
    }

    @Override
    protected Object determineCurrentLookupKey() {
        return DynamicDataSource.dataSourceKey.get();
    }

    public static void setDataSource(String dataSource) {
        DynamicDataSource.dataSourceKey.set(dataSource);
        DynamicDataSource dynamicDataSource = (DynamicDataSource) SpringUtils.getBean("dataSource");
        dynamicDataSource.afterPropertiesSet();
    }

    public static String getDataSource() {
        return DynamicDataSource.dataSourceKey.get();
    }

    public static void clear() {
        DynamicDataSource.dataSourceKey.remove();
    }
}
import com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceBuilder;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.DependsOn;
import org.springframework.context.annotation.Primary;
import javax.sql.DataSource;

@Configuration
public class DataSourceConfig {

    @Bean
    @ConfigurationProperties("spring.datasource.druid")
    public DataSource defaultDataSource() {
        return DruidDataSourceBuilder.create().build();
    }

    @Bean
    @Primary
    @DependsOn({"springUtils", "defaultDataSource"})
    public DynamicDataSource dataSource() {
        DynamicDataSource dynamicDataSource = new DynamicDataSource();
        dynamicDataSource.setTargetDataSources(DynamicDataSource.dataSourcesMap);
        return dynamicDataSource;
    }
}

使用時直接調用DynamicDataSource.setDataSource(DataSource dataSource)方法即可,使用完后調用DynamicDataSource.clear()防止內存泄漏並重置默認數據源。

附上詳細使用方法:

        DruidDataSource druidDataSource = new DruidDataSource();
        druidDataSource.setUrl("jdbc:mysql://localhost:3306/sys?characterEncoding=utf-8&useSSL=false&serverTimezone=UTC&useAffectedRows=true");
        druidDataSource.setUsername("root");
        druidDataSource.setPassword("root");
        DynamicDataSource.dataSourcesMap.put("dbkey", druidDataSource);
        DynamicDataSource.setDataSource("dbkey");
        此時數據源已切換到druidDataSource ,調用自己的業務方法即可。
        使用完后調用DynamicDataSource.clear();重置為默認數據源。

附上工具類SpringUtils :

import lombok.Getter;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;

@Component
public final class SpringUtils implements ApplicationContextAware {

    @Getter
    private static ApplicationContext applicationContext;

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        if (SpringUtils.applicationContext == null) {
            SpringUtils.applicationContext = applicationContext;
        }
    }

    public static <T> T getBean(Class<T> clazz) {
        return SpringUtils.applicationContext.getBean(clazz);
    }

    public static Object getBean(String name) {
        return SpringUtils.applicationContext.getBean(name);
    }

    public static String getProperty(String key) {
        return SpringUtils.applicationContext.getEnvironment().getProperty(key);
    }
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM