【动态设置数据源】DynamicDataSource 继承AbstractRoutingDataSource DruidDataSource

一、默认数据源

druid.properties
 默认初始化数据库:

spring.datasource.driverClassName=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://10.129.0.144:3306/abc?connectTimeout=30000&socketTimeout=60000&serverTimezone=GMT%2B8&characterEncoding=utf-8
spring.datasource.username=root
spring.datasource.password=root

initialSize=5
maxActive=10
maxWait=3000



package com.atguigu.config;

import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.support.http.StatViewServlet;
import com.alibaba.druid.support.http.WebStatFilter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.context.annotation.*;
import org.springframework.stereotype.Component;

import javax.sql.DataSource;
import java.sql.SQLException;

/**
 * DRUID 数据库连接池类
 * @author  
 * @date 2020/11/19 22:19
 * @version V1.0.0
 */
@Configuration
@Slf4j
@PropertySource("classpath:druid.properties")
public class DruidConfig {

    private static final String DB_PREFIX = "spring.datasource";

    /**
     * 数据源动态初始化的管理类
     * @return
     */
    @Bean(name = "dynamicDataSource")
    @Primary
    @DependsOn({"springUtils", "defaultDataSource"})
    public DynamicDataSource dataSource() {
        DynamicDataSource dynamicDataSource = new DynamicDataSource();
        dynamicDataSource.setTargetDataSources(DynamicDataSource.dataSourcesMap);
        return dynamicDataSource;
    }

    @Component
    @ConfigurationProperties(prefix = DB_PREFIX)
    static class IDataSourceProperties {
        private String url;
        private String username;
        private String password;
        private String driverClassName;
        private int initialSize;
        private int minIdle;
        private int maxActive;
        private int maxWait;
        private int timeBetweenEvictionRunsMillis;
        private int minEvictableIdleTimeMillis;
        private String validationQuery;
        private boolean testWhileIdle;
        private boolean testOnBorrow;
        private boolean testOnReturn;
        private boolean poolPreparedStatements;
        private int maxPoolPreparedStatementPerConnectionSize;
        private String filters;
        private String connectionProperties;

        @Bean     //声明其为Bean实例
        //@Primary  //在同样的DataSource中,首先使用被标注的DataSource
        public DataSource defaultDataSource() {
            DruidDataSource datasource = new DruidDataSource();
            datasource.setUrl(url);
            datasource.setUsername(username);
            datasource.setPassword(password);
            datasource.setDriverClassName(driverClassName);

            //configuration
            datasource.setInitialSize(initialSize);
            datasource.setMinIdle(minIdle);
            datasource.setMaxActive(maxActive);
            datasource.setMaxWait(maxWait);
            datasource.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis);
            datasource.setMinEvictableIdleTimeMillis(minEvictableIdleTimeMillis);
            datasource.setValidationQuery(validationQuery);
            datasource.setTestWhileIdle(testWhileIdle);
            datasource.setTestOnBorrow(testOnBorrow);
            datasource.setTestOnReturn(testOnReturn);
            datasource.setPoolPreparedStatements(poolPreparedStatements);
            datasource.setMaxPoolPreparedStatementPerConnectionSize(maxPoolPreparedStatementPerConnectionSize);
            try {
                datasource.setFilters(filters);
            } catch (SQLException e) {
                log.error("druid configuration initialization filter: " , e);
            }
            datasource.setConnectionProperties(connectionProperties);
            try {
                datasource.init();
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }
            return datasource;
        }

        public String getUrl() {
            return url;
        }

        public void setUrl(String url) {
            this.url = url;
        }

        public String getUsername() {
            return username;
        }

        public void setUsername(String username) {
            this.username = username;
        }

        public String getPassword() {
            return password;
        }

        public void setPassword(String password) {
            this.password = password;
        }

        public String getDriverClassName() {
            return driverClassName;
        }

        public void setDriverClassName(String driverClassName) {
            this.driverClassName = driverClassName;
        }

        public int getInitialSize() {
            return initialSize;
        }

        public void setInitialSize(int initialSize) {
            this.initialSize = initialSize;
        }

        public int getMinIdle() {
            return minIdle;
        }

        public void setMinIdle(int minIdle) {
            this.minIdle = minIdle;
        }

        public int getMaxActive() {
            return maxActive;
        }

        public void setMaxActive(int maxActive) {
            this.maxActive = maxActive;
        }

        public int getMaxWait() {
            return maxWait;
        }

        public void setMaxWait(int maxWait) {
            this.maxWait = maxWait;
        }

        public int getTimeBetweenEvictionRunsMillis() {
            return timeBetweenEvictionRunsMillis;
        }

        public void setTimeBetweenEvictionRunsMillis(int timeBetweenEvictionRunsMillis) {
            this.timeBetweenEvictionRunsMillis = timeBetweenEvictionRunsMillis;
        }

        public int getMinEvictableIdleTimeMillis() {
            return minEvictableIdleTimeMillis;
        }

        public void setMinEvictableIdleTimeMillis(int minEvictableIdleTimeMillis) {
            this.minEvictableIdleTimeMillis = minEvictableIdleTimeMillis;
        }

        public String getValidationQuery() {
            return validationQuery;
        }

        public void setValidationQuery(String validationQuery) {
            this.validationQuery = validationQuery;
        }

        public boolean isTestWhileIdle() {
            return testWhileIdle;
        }

        public void setTestWhileIdle(boolean testWhileIdle) {
            this.testWhileIdle = testWhileIdle;
        }

        public boolean isTestOnBorrow() {
            return testOnBorrow;
        }

        public void setTestOnBorrow(boolean testOnBorrow) {
            this.testOnBorrow = testOnBorrow;
        }

        public boolean isTestOnReturn() {
            return testOnReturn;
        }

        public void setTestOnReturn(boolean testOnReturn) {
            this.testOnReturn = testOnReturn;
        }

        public boolean isPoolPreparedStatements() {
            return poolPreparedStatements;
        }

        public void setPoolPreparedStatements(boolean poolPreparedStatements) {
            this.poolPreparedStatements = poolPreparedStatements;
        }

        public int getMaxPoolPreparedStatementPerConnectionSize() {
            return maxPoolPreparedStatementPerConnectionSize;
        }

        public void setMaxPoolPreparedStatementPerConnectionSize(int maxPoolPreparedStatementPerConnectionSize) {
            this.maxPoolPreparedStatementPerConnectionSize = maxPoolPreparedStatementPerConnectionSize;
        }

        public String getFilters() {
            return filters;
        }

        public void setFilters(String filters) {
            this.filters = filters;
        }

        public String getConnectionProperties() {
            return connectionProperties;
        }

        public void setConnectionProperties(String connectionProperties) {
            this.connectionProperties = connectionProperties;
        }

        @Bean
        public ServletRegistrationBean<StatViewServlet> druidServlet() {// 主要实现web监控的配置处理
            ServletRegistrationBean<StatViewServlet> servletRegistrationBean = new ServletRegistrationBean<>(
                    new StatViewServlet(), "/druid/*");//表示进行druid监控的配置处理操作
            servletRegistrationBean.addInitParameter("allow", "127.0.0.1,192.168.0.12");//白名单
            servletRegistrationBean.addInitParameter("deny", "129.168.1.12");//黑名单
            servletRegistrationBean.addInitParameter("loginUsername", "root");//用户名
            servletRegistrationBean.addInitParameter("loginPassword", "123456");//密码
            servletRegistrationBean.addInitParameter("resetEnable", "false");//是否可以重置数据源
            return servletRegistrationBean;

        }

        @Bean    //监控
        public FilterRegistrationBean<WebStatFilter> filterRegistrationBean(){
            FilterRegistrationBean<WebStatFilter> filterRegistrationBean=new FilterRegistrationBean<>();
            filterRegistrationBean.setFilter(new WebStatFilter());
            filterRegistrationBean.addUrlPatterns("/*");//所有请求进行监控处理
            filterRegistrationBean.addInitParameter("exclusions", "*.js,*.gif,*.jpg,*.css,/druid/*");//排除
            return filterRegistrationBean;
        }
    }
}




二、数据源管理类DynamicDataSource

获取指定名称Bean的工具类:

package com.atguigu.util;

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

/**
 * Description: Spring工具类
 *
 * @Author:
 * @Date: 2021-04-27 23:51
 * @version: V1.0.0
 */
@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 Object getBean(String name) {
        return SpringUtils.applicationContext.getBean(name);
    }
}




 
管理类:

package com.atguigu.config;

import com.alibaba.druid.pool.DruidDataSource;
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
import com.atguigu.util.SpringUtils;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * Description: 动态数据源
 *
 * @Author: zhx & moon hongxu_1234@163.com
 * @Date: 2021-04-27 23:49
 * @version: V1.0.0
 */
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"));
    }

    /**
     * 获取需要使用的DataSource的key值,根据key从resolvedDataSources这个map里取出对应的DataSource
     * @return
     */
    @Override
    protected Object determineCurrentLookupKey() {
        return DynamicDataSource.dataSourceKey.get();
    }

    /**
     * 设置动态数据源
     * @param dataSource
     */
    public static void setDataSource(String dataSource) {
        DynamicDataSource.dataSourceKey.set(dataSource);
        DynamicDataSource dynamicDataSource = (DynamicDataSource) SpringUtils.getBean("dynamicDataSource");
        dynamicDataSource.afterPropertiesSet();
    }

    /**
     * 恢复默认数据源
     */
    public static void clear() {
        DynamicDataSource.dataSourceKey.remove();
    }

    /**
     * 销毁旧的数据源
     */
    public static void close() {

        DynamicDataSource dynamicDataSource = (DynamicDataSource) SpringUtils.getBean("dynamicDataSource");
        DruidDataSource lastDruidDataSource = (DruidDataSource)dynamicDataSource.determineTargetDataSource();
        lastDruidDataSource.close();
    }
}


三、关于使用

保持单一数据源,接口直接切换

package com.atguigu.controller;

import com.alibaba.druid.pool.DruidDataSource;
import com.atguigu.config.DynamicDataSource;
import com.atguigu.entity.UserEntity;
import com.atguigu.mapper.UserMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;

/**
 * @author Administrator
 */
@RestController
public class HelloController {

    @Autowired
    UserMapper userMapper;

    @GetMapping("/dataSource")
    public void dataSource(int type){
        //销毁上一个数据源
        DynamicDataSource.close();
        if(type==0){
            DruidDataSource druidDataSource = new DruidDataSource();
            druidDataSource.setUrl("jdbc:postgresql://192.168.31.51:5432/database1");
            druidDataSource.setUsername("postgres");
            druidDataSource.setPassword("passwd");
            DynamicDataSource.clear();
            DynamicDataSource.dataSourcesMap.put("defaultDataSource", druidDataSource);
            DynamicDataSource.setDataSource("defaultDataSource");
            UserEntity userEntity = userMapper.selectUser();
            System.out.println(userEntity.toString());
        }else {
            DruidDataSource druidDataSource = new DruidDataSource();
            druidDataSource.setUrl("jdbc:postgresql://192.168.31.51:5432/database2");
            druidDataSource.setUsername("postgres");
            druidDataSource.setPassword("passwd");
            DynamicDataSource.clear();
            DynamicDataSource.dataSourcesMap.put("defaultDataSource", druidDataSource);
            DynamicDataSource.setDataSource("defaultDataSource");
            UserEntity userEntity = userMapper.selectUser();
            System.out.println(userEntity.toString());
        }
    }
}

参考:https://blog.csdn.net/weixin_42176639/article/details/116245539

https://www.cnblogs.com/wsss/p/5475057.html

https://blog.csdn.net/syslbjjly/article/details/93492535

https://www.jianshu.com/p/c57772c8b802

https://blog.csdn.net/yizhenn/article/details/53965552

原文地址:https://www.cnblogs.com/zzsuje/p/15411304.html