springboot多数据源切换

       实际工作中,我们会遇到springboot项目初始化启动时候,不能指定具体连接哪个数据源的时候,不同的接口连接不同的数据源或者前端页面指定连接某个数据源等等情况,就会遇到动态数据源切换的问题。

一.通用的动态数据源切换场景

Spring boot提供了AbstractRoutingDataSource 根据用户定义的规则选择当前的数据源,这样我们可以在执行查询之前,设置使用的数据源。实现可动态路由的数据源,在每次数据库查询操作前执行。它的抽象方法 determineCurrentLookupKey() 决定使用哪个数据源.

1.继承AbstractRoutingDataSource,重写determineCurrentLookupKey方法

public class DynamicDataSource extends AbstractRoutingDataSource {

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

   private static Map<Object,Object> dataSourceMap = new ConcurrentHashMap<>(10);

   static {

        dataSourceMap .put("defaultDataSource", SpringUtils.getBean("defaultDataSource"));

   }

    @Override

    protected Object determineCurrentLookupKey() {

        return DynamicDataSource.dataSourceKey.get();

    }

    public static void serDataSource(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();

 

    }

2.把AbstractRoutingDataSource注入到容器中

@Configuration

public class DataSourceConfig{

     @Bean

     @ConfigurationProperties("spring.datasource.druid")

    public DataSource defaultDataSource(){

         return DruidDataSourceBuilder.create().builder();

     }

     @Bean
     @Primary

     @DependsOn({"springUtils","defaultDataSource"})
    public DynamicDataSource dataSource() {
       DynamicDataSource dynamicDataSource  = new DynamicDataSource ();

       dynamicDataSource.setTargetDataSource(DynamicDataSource .dataSourceMap );

       return dynamicDataSource ;
    }

}

3.实现SpringUtils工具类并注入到spring容器中

@Component
public class SpringUtils implements ApplicationContextAware {
 
    private static ApplicationContext applicationContext;
 
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }
 
    public static <T> T getBean(Class<T> tClass){
        return applicationContext.getBean(tClass);
    }
 
    public static Object getBean(String name) {
        return applicationContext.getBean(name);
    }
 
    public static HttpServletRequest getCurrentReq() {
        ServletRequestAttributes requestAttrs = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        if (requestAttrs == null) {
            return null;
        }
        return requestAttrs.getRequest();
    }
 
    public static String getMessage(String code, Object... args) {
        LocaleResolver localeResolver = getBean(LocaleResolver.class);
        Locale locale = localeResolver.resolveLocale(getCurrentReq());
        return applicationContext.getMessage(code, args, locale);
    }

   public satic String getProperty(String key){

       return SpringUtils.applicationContext.getEnvironment.getProperty(key);

   }
 
}

4.自定义注解和切面,实现方法级别是否切换数据源

@Document

@Retention(retentionPolicy.RUNTIME)

@Target(ElementType.METHOD)

public @interface OperDataSource {

}

 

@Component
@Aspect
public class DataSourceAspect {

    @Autowired

    private DataSourceProperties basicProperties;


    @Pointcut("@annotation(com.xxxxxx.OperDataSource )")
    public void dataSourcePointCut(){

    }

    @Before(value="dataSourcePointCut()")
    public void beforeMerhod(JoinPoint jp){
       DruidDataSource druidDataSource = new DruidDataSource();

       druidDataSource.setUrl(basicProperties.getUrl());

       druidDataSource.setUsername(basicProperties.getUsername());

       druidDataSource.setPassword(basicProperties.getPassword());

       DynamicDataSource.dataSourceMap.put("dbKey",druidDataSource);
        DataSourceContextHolder.setDataSource("dbKey");
    }

    @After("dataSourcePointCut()")
    public void afterMethod(JoinPoint jp){
        DynamicDataSource.clear();
    }
}

二. 页面切换数据源场景

1.排除掉Druid自动注入

@SpringBootApplication(exclude = {DruidDataSourceAutoConfigure.class})

2.手动实现DruidDataSource的bean

@Configuration

public class DataSourceConfig{

 private DataSourceProperties basicProperties;

  public DataSource dataSource() throws IOException, SQLException{

      DruidDataSource druidDataSource = DruidDataSourceBuilder.create().buid();

      druidDataSource.restart();

      druidDataSource.setPassword(Base64.Encoder getEncoder(basicProperties.getPassword()));

  }  

}

3.自定义接口,实现重新设置数据源

DruidDataSource druidDataSource = (DruidDataSource)SpringUtils.getBean("dataSource");

druidDataSource.restart();

druidDataSource.setDriverClassName(driverClassName);

druidDataSource.setUrl(url);

......

 如果需要改写yml文件内容

需要引入

<dependency>
    <groupId>org.yaml</groupId>
    <artifactId>snakeyaml</artifactId>
    <version>1.26</version>
</dependency>

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

彼岸花@开

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值