动态数据源配置

动态数据源注解

package com.nikooh.server.annotations;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * @Description: 动态数据源注解
 * @Author: nikooh
 * @Date: 2020/09/15 : 16:25
 */
@Target({ElementType.METHOD, ElementType.TYPE, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface DataSource {

    /**
     * 数据源信息,默认primary
     *
     * @return
     */
    String value() default "primary";
}

使用ThreadLocal装配DataSourceType

package com.nikooh.server.aspects;


import com.nikooh.server.enums.DataSourceTypeEnum;

/**
 * @Description: DataSourceType
 * @Author: nikooh
 * @Date: 2020/09/15 : 16:34
 */
public class DataSourceType {


    /**
     * 使用ThreadLocal保证线程安全
     */
    private static final ThreadLocal<DataSourceTypeEnum> TYPE = new ThreadLocal<>();

    /**
     * 往当前线程里设置数据源类型
     *
     * @param dataSourceType
     */
    public static void setDataBaseType(DataSourceTypeEnum dataSourceType) {
        if (dataSourceType == null) {
            throw new NullPointerException();
        }
        TYPE.set(dataSourceType);
    }

    /**
     * 获取数据源类型
     *
     * @return
     */
    public static DataSourceTypeEnum getDataSourceType() {
        return TYPE.get() == null ? DataSourceTypeEnum.PRIMARY : TYPE.get();
    }

    /**
     * 清空数据类型
     */
    public static void clearDataSourceType() {
        TYPE.remove();
    }
}

配置动态数据源切面

package com.nikooh.server.aspects;

import com.nikooh.server.annotations.DataSource;
import com.nikooh.server.enums.DataSourceTypeEnum;
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.stereotype.Component;

/**
 * @Description: 动态数据源切面
 * @Author: nikooh
 * @Date: 2020/09/15 : 16:27
 */
@Component
@Aspect
public class DynamicDataSourceAspect {

    private static final Logger LOGGER = LoggerFactory.getLogger(DynamicDataSourceAspect.class);

    /**
     * 前置通知:设置数据源信息
     *
     * @param point      point
     * @param dataSource 动态数据源注解
     */
    @Before("@annotation(dataSource)")
    public void changeDataSource(JoinPoint point, DataSource dataSource) {
        DataSourceTypeEnum dataSourceType;
        if (null == dataSource) {
            //没有注解,默认使用主数据源
            dataSourceType = DataSourceTypeEnum.PRIMARY;
        } else {
            String value = dataSource.value();
            dataSourceType = DataSourceTypeEnum.parseByValue(value);
        }
        LOGGER.info(">>>>>>>>>> 当前线程[{}]使用数据源:[{}] <<<<<<<<<<", Thread.currentThread().getId(), dataSourceType.getValue());
        DataSourceType.setDataBaseType(dataSourceType);
    }

    /**
     * 后置通知:清除数据源信息
     *
     * @param point      point
     * @param dataSource 动态数据源注解
     */
    @After("@annotation(dataSource)")
    public void restoreDataSource(JoinPoint point, DataSource dataSource) {
        LOGGER.info(">>>>>>>>>> 当前线程[{}]已清除数据源:[{}] <<<<<<<<<<", Thread.currentThread().getId(), DataSourceType.getDataSourceType().getValue());
        DataSourceType.clearDataSourceType();
    }

}

配置类继承AbstractRoutingDataSource类实现切换

package com.nikooh.server.aspects;

import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;

/**
 * @Description: 动态切换数据源
 * @Author: nikooh
 * @Date: 2020/09/15 : 16:40
 */
public class DynamicDataSource extends AbstractRoutingDataSource {

    /**
     * 程序运行时动态切换数据源
     *
     * @return
     */
    @Override
    protected Object determineCurrentLookupKey() {
        //返回数据源
        return DataSourceType.getDataSourceType();
    }

}

配置动态数据源

package com.nikooh.server.config;

import com.nikooh.server.aspects.DynamicDataSource;
import com.nikooh.server.enums.DataSourceTypeEnum;
import com.nikooh.server.properties.PrimaryDateSourceProperties;
import com.nikooh.server.properties.SecondaryDataSourceProperties;
import com.zaxxer.hikari.HikariDataSource;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.security.SecurityProperties;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.jdbc.DataSourceBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;

import javax.sql.DataSource;
import java.util.HashMap;
import java.util.Map;

/**
 * @Description: 动态数据源配置
 * @Author: nikooh
 * @Date: 2020/09/15 : 16:42
 */
@Configuration
@MapperScan(basePackages = "com.nikooh.server.mapper.*", sqlSessionFactoryRef = "sqlSessionFactory")
public class DynamicDataSourceConfig {

    @Bean(name = "primaryDataSource")
    public DataSource getPrimaryDateSource(PrimaryDateSourceProperties primaryDateSourceProperties) {
        return DataSourceBuilder.create(primaryDateSourceProperties.getClass().getClassLoader())
                .type(HikariDataSource.class)
                .driverClassName(primaryDateSourceProperties.getDriverClassName())
                .url(primaryDateSourceProperties.getUrl())
                .username(primaryDateSourceProperties.getUserName())
                .password(primaryDateSourceProperties.getPassword())
                .build();
    }

    @Bean(name = "secondaryDataSource")
    public DataSource getSecondaryDateSource(SecondaryDataSourceProperties secondaryDataSourceProperties) {
        return DataSourceBuilder.create(secondaryDataSourceProperties.getClass().getClassLoader())
                .type(HikariDataSource.class)
                .driverClassName(secondaryDataSourceProperties.getDriverClassName())
                .url(secondaryDataSourceProperties.getUrl())
                .username(secondaryDataSourceProperties.getUserName())
                .password(secondaryDataSourceProperties.getPassword())
                .build();
    }

    @Bean(name = "dynamicDataSource")
    public DynamicDataSource dataSource(@Qualifier("primaryDataSource") DataSource primaryDataSource,
                                        @Qualifier("secondaryDataSource") DataSource secondaryDataSource) {
        //这个地方是比较核心的targetDataSource 集合是我们数据库和名字之间的映射
        Map<Object, Object> targetDataSource = new HashMap<>();
        targetDataSource.put(DataSourceTypeEnum.PRIMARY, primaryDataSource);
        targetDataSource.put(DataSourceTypeEnum.SECONDARY, secondaryDataSource);
        DynamicDataSource dataSource = new DynamicDataSource();
        dataSource.setTargetDataSources(targetDataSource);
        //设置默认对象
        dataSource.setDefaultTargetDataSource(primaryDataSource);
        return dataSource;
    }

    @Bean(name = "sqlSessionFactory")
    public SqlSessionFactory sqlSessionFactory(@Qualifier("dynamicDataSource") DataSource dynamicDataSource)
            throws Exception {
        SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
        bean.setDataSource(dynamicDataSource);
        bean.setMapperLocations(
                //设置xml文件路径
                new PathMatchingResourcePatternResolver().getResources("classpath*:**/mapper/**/*Mapper.xml"));
        return bean.getObject();
    }

}

配置读取properties

package com.nikooh.server.properties;

import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;

/**
 * @Description:
 * @Author: nikooh
 * @Date: 2020/09/15 : 17:42
 */
@Component
@ConfigurationProperties(prefix = "spring.datasource.primary")
public class PrimaryDateSourceProperties {

    private String driverClassName;

    private String url;

    private String userName;

    private String password;

    public String getDriverClassName() {
        return driverClassName;
    }

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

    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;
    }
}

package com.nikooh.server.properties;

import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;

/**
 * @Description:
 * @Author: nikooh
 * @Date: 2020/09/15 : 17:56
 */
@Component
@ConfigurationProperties(prefix = "spring.datasource.secondary")
public class SecondaryDataSourceProperties {

    private String driverClassName;

    private String url;

    private String userName;

    private String password;

    public String getDriverClassName() {
        return driverClassName;
    }

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

    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;
    }
}

resource中的数据源连接信息配置

#----------------------------primary datasource-------------------------
spring.datasource.primary.driverClassName=com.mysql.jdbc.Driver
spring.datasource.primary.url=jdbc:mysql://101.132.238.100:3306/db_nikooh?characterEncoding=UTF-8&serverTimezone=UTC
spring.datasource.primary.username=nikooh
spring.datasource.primary.password=199312
#----------------------------secondary datasource-------------------------
spring.datasource.secondary.driverClassName=com.mysql.jdbc.Driver
spring.datasource.secondary.url=jdbc:mysql://101.132.238.100:3306/db_user?characterEncoding=UTF-8&serverTimezone=UTC
spring.datasource.secondary.username=nikooh
spring.datasource.secondary.password=199312
spring.main.allow-bean-definition-overriding=true

使用方法

动态数据源使用方式

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值