springboot druid配置多数据源

mybatisplus官方提供的多数据源和druid匹配不上,应该是springboot3之后导致spring.factories失效导致的,手写一下,测试切换数据源,事务都没问题

1.依赖

springboot版本是3.2.5

<dependency>
      <groupId>com.mysql</groupId>
      <artifactId>mysql-connector-j</artifactId>
      </dependency>
<dependency>
      <groupId>com.alibaba</groupId>
      <artifactId>druid-spring-boot-starter</artifactId>
      <version>1.2.8</version>
</dependency>
<dependency>
      <groupId>org.mybatis.spring.boot</groupId>
      <artifactId>mybatis-spring-boot-starter</artifactId>
      <version>3.0.3</version>
</dependency>
<dependency>
      <groupId>com.baomidou</groupId>
      <artifactId>mybatis-plus-boot-starter</artifactId>
      <version>3.5.5</version>
</dependency>

2.注册配置

package com.ahli.filesystem.config.datasource;

import lombok.Data;
import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;

import java.util.Map;

@Configuration
@ConfigurationProperties(prefix = "spring.datasource.dynamic")
@Data
public class DynamicConfigProperties {
    private String primary;
    private Map<String, DataSourceProperties> datasource;
}

3.配置文件

spring:
  datasource:
    dynamic:
      primary: write
      datasource:
        write:
          url: jdbc:mysql://127.0.0.1:3306/filesystem?useSSL=true&characterEncoding=UTF-8&serverTimezone=GMT%2B8&nullCatalogMeansCurrent=true
          username: root
          password: password
          driver-class-name: com.mysql.cj.jdbc.Driver
        read:
          url: jdbc:mysql://127.0.0.1:3307/filesystem?useSSL=true&characterEncoding=UTF-8&serverTimezone=GMT%2B8&nullCatalogMeansCurrent=true
          username: root
          password: password
          driver-class-name: com.mysql.cj.jdbc.Driver
    druid:
      initial-size: 20
      min-idle: 5
      max-active: 20
      max-wait: 60000

4.动态数据源

在配置类里把这个标记为primary,切换数据源才有效

package com.ahli.filesystem.config.datasource;

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

public class DynamicDataSource  extends AbstractRoutingDataSource {
    @Override
    protected Object determineCurrentLookupKey() {
        return DataSourceContextHolder.getDataSource();
    }
}

5.数据源配置

可以修改成springboot的register bean,这里就直接写吧

package com.ahli.filesystem.config.datasource;

import cn.hutool.extra.spring.SpringUtil;
import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceBuilder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;

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

@Configuration
public class DynamicDataSourceConfig implements ApplicationContextAware {
    @Autowired
    private DynamicConfigProperties dynamicConfigProperties;

    private ApplicationContext applicationContext;

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }

    @PostConstruct
    public void registerDataSource(){
        Map<String, DataSourceProperties> datasources = dynamicConfigProperties.getDatasource();
        GenericApplicationContext genericContext = (GenericApplicationContext) applicationContext;
        datasources.forEach((k, v)->{
            DruidDataSource dataSource = DruidDataSourceBuilder.create().build();
            dataSource.setUrl(v.getUrl());
            dataSource.setUsername(v.getUsername());
            dataSource.setPassword(v.getPassword());
            dataSource.setDriverClassName(v.getDriverClassName());
            genericContext.registerBean(k, DataSource.class, ()->dataSource);
        });
    }

    @Primary
    @Bean
    public DataSource dynamicDataSource() {
        DynamicDataSource dynamicDataSource = new DynamicDataSource();
        Map<Object, Object> targetDataSources = new HashMap<>();
        dynamicConfigProperties.getDatasource().forEach((k, v)->{
            DataSource datasource = SpringUtil.getBean(k);
            if (dynamicConfigProperties.getPrimary().equals(k)) {
                dynamicDataSource.setDefaultTargetDataSource(datasource);
            }
            targetDataSources.put(k, datasource);
        });
        dynamicDataSource.setTargetDataSources(targetDataSources);
        return dynamicDataSource;
    }
}

 6.数据源holder

package com.ahli.filesystem.config.datasource;

public class DataSourceContextHolder {
    private static final ThreadLocal<String> contextHolder = new ThreadLocal<>();
    
    public static void setDataSource(String dbName) {
        contextHolder.set(dbName);
    }
    
    public static String getDataSource() {
        return contextHolder.get();
    }
    
    public static void clearDataSource() {
        contextHolder.remove();
    }
}

7.切换数据源注解

package com.ahli.filesystem.config.datasource;

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

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.METHOD})
public @interface DS {
    String value() default "${spring.datasource.dynamic.primary}";
}

8.切换数据源切面

package com.ahli.filesystem.config.datasource;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;

@Component
@Aspect
public class DynamicDataSourceAspect {
    @Pointcut("@annotation(DS)")
    public void dynamicDataSourcePointCut() {}

    @Around("dynamicDataSourcePointCut()")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        String dataSourceKey;

        Class<?> aClass = joinPoint.getTarget().getClass();
        DS annotation = null;
        if (aClass.isAnnotationPresent(DS.class)) {
            annotation = aClass.getAnnotation(DS.class);
        }
        
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        DS annotationMethod = null;
        if (signature.getMethod().isAnnotationPresent(DS.class)) {
            annotationMethod = signature.getMethod().getAnnotation(DS.class);
        }
        if (annotationMethod != null) {
            dataSourceKey = annotationMethod.value();
        } else {
            dataSourceKey = annotation.value();
        }
        
        DataSourceContextHolder.setDataSource(dataSourceKey);
        try {
            return joinPoint.proceed();
        } finally {
            DataSourceContextHolder.clearDataSource();
        }
    }
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值