多数据源的创建与切换(单例)

项目需求背景

最近做项目的时候碰到一个需求还蛮不错的分享一下。
简化版:
根据输入的数据源信息(url,driverClassName,username,password)来连接新数据源,同时获取该数据源下所有的数据库名字。
这里采用的是dynamic动态数据库完成
直接上代码

<!-- 动态数据库 -->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>dynamic-datasource-spring-boot-starter</artifactId>
            <version>3.2.1</version>
        </dependency>

dynamic-datasource-spring-boot-starter 是一个基于springboot的快速集成多数据源的启动器。

@Service
public class DbManagerServiceImpl implements DbManagerService {
    
    

   
    @Resource
    private DataSourceCreator dataSourceCreator;
    
    @Override
    public void test(DataSourceProperty dataSourceProperty) {
    
    
        try {
    
    
            DynamicUtil.getInstance().createNewDataSource(dataSourceProperty,dataSourceCreator);

            List<String> list = commonSqlMapper.getAllDataBase();

            list.forEach(s -> System.out.println(s));
            return list;
        } catch (Exception e) {
    
    
            e.printStackTrace();
        } finally {
    
    
            DynamicDataSourceContextHolder.poll();
        }

    }
}

工具类:

import com.baomidou.dynamic.datasource.DynamicRoutingDataSource;
import com.baomidou.dynamic.datasource.creator.DataSourceCreator;
import com.baomidou.dynamic.datasource.spring.boot.autoconfigure.DataSourceProperty;
import com.baomidou.dynamic.datasource.toolkit.DynamicDataSourceContextHolder;

import javax.sql.DataSource;

public class DynamicUtil {
    
    


    private  static volatile DynamicRoutingDataSource instance2= null;

    private static volatile DynamicUtil instance3 = null;

    public DynamicUtil() {
    
    
    }


    public static synchronized DynamicUtil getInstance() {
    
    
        //在getInstance方法上加同步
        if (instance3 == null) {
    
    
            instance3 = new DynamicUtil();
        } else {
    
    
            System.out.println("已经有一个数据源创建工具类,不能产生新的!");
        }
        return instance3;
    }

    public static synchronized DynamicRoutingDataSource getInstance2() {
    
    
        //在getInstance方法上加同步
        if (instance2 == null) {
    
    
            instance2 = new DynamicRoutingDataSource();
        } else {
    
    
            System.out.println("已经有一个数据源管理器,不能产生新的!");
        }
        return instance2;
    }

    public  void  createNewDataSource(DataSourceProperty dataSourceProperty,DataSourceCreator dataSourceCreator)
    {
    
    
        DynamicRoutingDataSource drds2 = getInstance2();
        System.out.println(dataSourceProperty);
        //创建数据源并添加到系统中管理
        DataSource dataSource = dataSourceCreator.createDataSource(dataSourceProperty);
        String userName = dataSourceProperty.getUsername();
        drds2.addDataSource(userName, dataSource);
        DynamicDataSourceContextHolder.push(userName);
    }
}

DataSourceProperty 是封装好的实体包含了用户名,url等信息
工具类采用单例模式,这里讲一下自己当时的误区

(要知道,DataSourceCreator是属于依赖,所以自动注入的时候不能放在另一个对象里,也就是不能放工具类里注入,因为自动注入实在编译期就分配好内存并放在spring容器中。)

工具类使用单例模式
push之后就可以使用新数据源了,然后业务逻辑完成后进行poll删除当前数据源
之后就会使用yml里的默认数据源
当然如果数据源确定好了也可以直接在yml里写死,通过注解切换。