• Springboot-配置多数据源-接口切换


    Application添加注解: @Import({DynamicDataSourceRegister.class}) 

    application.xml配置从数据源:

    slave:
        datasource:
            names: name1 ,name2
            name1:
                driver-class-name: com.mysql.jdbc.Driver
                names: datasource1
                url:
                username:
                password:
                type: com.alibaba.druid.pool.DruidDataSource
            name2:
                driver-class-name: com.mysql.jdbc.Driver
                names: datasource2
                url: 
                username: 
                password:
                type: com.alibaba.druid.pool.DruidDataSource
    数据源注册 DynamicDataSourceRegister.java
    public class DynamicDataSourceRegister implements ImportBeanDefinitionRegistrar, EnvironmentAware {
    
        private org.slf4j.Logger logger = LoggerFactory.getLogger(DynamicDataSourceRegister.class);
        public static  Environment environment;
        //指定默认数据源(springboot2.0默认数据源是hikari如何想使用其他数据源可以自己配置)
        private static final String DATASOURCE_TYPE_DEFAULT = "com.zaxxer.hikari.HikariDataSource";
        //默认数据源
        private DataSource defaultDataSource;
        //用户自定义数据源
        private Map<String, DataSource> slaveDataSources = new HashMap<>();
    
        @Override
        public void setEnvironment(Environment environment) {
            initDefaultDataSource(environment);
            initSlaveDataSources(environment);
            this.environment = environment;
        }
    
        private void initDefaultDataSource(Environment env) {
            // 读取主数据源
            Map<String, Object> dsMap = new HashMap<>();
            dsMap.put("driver", env.getProperty("spring.datasource.driver-class-name"));
            dsMap.put("url", env.getProperty("spring.datasource.url"));
            dsMap.put("username", env.getProperty("spring.datasource.username"));
            dsMap.put("password", env.getProperty("spring.datasource.password"));
            defaultDataSource = buildDataSource(dsMap);
        }
    
    
        private void initSlaveDataSources(Environment env) {
            // 读取配置文件获取更多数据源
            String dsPrefixs = env.getProperty("slave.datasource.names");
            if(StringUtil.isNotEmpty(dsPrefixs)) {
                for (String dsPrefix : dsPrefixs.split(",")) {
                    // 多个数据源
                    Map<String, Object> dsMap = new HashMap<>();
                    dsMap.put("driver", env.getProperty("slave.datasource." + dsPrefix + ".driver-class-name"));
                    dsMap.put("url", env.getProperty("slave.datasource." + dsPrefix + ".url"));
                    dsMap.put("username", env.getProperty("slave.datasource." + dsPrefix + ".username"));
                    dsMap.put("password", env.getProperty("slave.datasource." + dsPrefix + ".password"));
                    DataSource ds = buildDataSource(dsMap);
                    slaveDataSources.put(dsPrefix, ds);
                }
            }
        }
    
    
        @Override
        public void registerBeanDefinitions(AnnotationMetadata annotationMetadata, BeanDefinitionRegistry beanDefinitionRegistry) {
            Map<Object, Object> targetDataSources = new HashMap<Object, Object>();
            //添加默认数据源
            targetDataSources.put("dataSource", this.defaultDataSource);
            DynamicDataSourceContextHolder.dataSourceIds.add("dataSource");
            //添加其他数据源
            targetDataSources.putAll(slaveDataSources);
            for (String key : slaveDataSources.keySet()) {
                DynamicDataSourceContextHolder.dataSourceIds.add(key);
            }
    
            //创建DynamicDataSource
            GenericBeanDefinition beanDefinition = new GenericBeanDefinition();
            beanDefinition.setBeanClass(DynamicDataSource.class);
            beanDefinition.setSynthetic(true);
            MutablePropertyValues mpv = beanDefinition.getPropertyValues();
            mpv.addPropertyValue("defaultTargetDataSource", defaultDataSource);
            mpv.addPropertyValue("targetDataSources", targetDataSources);
            //注册 - BeanDefinitionRegistry
            beanDefinitionRegistry.registerBeanDefinition("dataSource", beanDefinition);
    
            logger.info("Dynamic DataSource Registry");
        }
    
        public DataSource buildDataSource(Map<String, Object> dataSourceMap) {
            try {
                Object type = dataSourceMap.get("type");
                if (type == null) {
                    type = DATASOURCE_TYPE_DEFAULT;// 默认DataSource
                }
                Class<? extends DataSource> dataSourceType;
                dataSourceType = (Class<? extends DataSource>) Class.forName((String) type);
                String driverClassName = dataSourceMap.get("driver").toString();
                String url = dataSourceMap.get("url").toString();
                String username = dataSourceMap.get("username").toString();
                String password = dataSourceMap.get("password").toString();
                // 自定义DataSource配置
                DataSourceBuilder factory = DataSourceBuilder.create().driverClassName(driverClassName).url(url)
                        .username(username).password(password).type(dataSourceType);
                return factory.build();
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            }
            return null;
        }
    }

    动态数据源上下文管理:DynamicDataSourceContextHolder.java

    public class DynamicDataSourceContextHolder {//存放当前线程使用的数据源类型信息
        private static final ThreadLocal<String> contextHolder = new ThreadLocal<String>();
        //存放数据源id
        public static List<String> dataSourceIds = new ArrayList<String>();
    
        //设置数据源
        public static void setDataSourceType(String dataSourceType) {
            contextHolder.set(dataSourceType);
        }
    
        //获取数据源
        public static String getDataSourceType() {
            return contextHolder.get();
        }
    
        //清除数据源
        public static void clearDataSourceType() {
            contextHolder.remove();
        }
    
        //判断当前数据源是否存在
        public static boolean isContainsDataSource(String dataSourceId) {
            return dataSourceIds.contains(dataSourceId);
        }
    }
    动态数据源  DynamicDataSource.java  -- AbstractRoutingDataSource(每执行一次数据库,动态获取DataSource)
    public class DynamicDataSource extends AbstractRoutingDataSource {
        @Override
        protected Object determineCurrentLookupKey() {
            return DynamicDataSourceContextHolder.getDataSourceType();
        }
    }
    动态数据源通知 DynamicDataSourceAspect.java
    @Aspect
    @Order(-1)//保证在@Transactional之前执行
    @Component
    public class DynamicDataSourceAspect {//改变数据源
        public void changeDataSource( String  targetDataSource) {
            if (StringUtil.isNotEmpty(targetDataSource) && DynamicDataSourceContextHolder.isContainsDataSource(targetDataSource)) {
                DynamicDataSourceContextHolder.setDataSourceType(targetDataSource);
            }
        }
    
        public void clearDataSource( String  targetDataSource) {
            DynamicDataSourceContextHolder.clearDataSourceType();
        }
    }

    换源API调用:

    @Autowired
    private DynamicDataSourceAspect dynamicDataSourceAspect;
    使用: dynamicDattaSourceAspect.changeDataSource(##数据源名称##);
    -----查询SQL业务----- dynamicDattaSourceAspect.clearDataSource(##数据源名称##);
    
    
  • 相关阅读:
    短信平台接口调用方法参考
    C#部分类与部分方法
    Oracle表字段类型更改的一个经验
    ueditor的上传文件漏洞(c#)
    判断一个文件是否是指定后缀名的文件
    利用FluorineFx的ByteArray上传图片
    FluorineFx 播放FLV 时堆棧溢出解决 FluorineFx NetStream.play 并发时,无法全部连接成功的解决办法
    Flex数据交互之Remoting[转]
    fluorinefx使用手册
    SharedObject使用:在FluorineFx.net与Flex中使用共享对象维护在线用户列表实例【转】
  • 原文地址:https://www.cnblogs.com/feecy/p/11847207.html
Copyright © 2020-2023  润新知