spring boot + druid 多数据源配置

废话不多说,直接上干货。

引入依赖

<!--mysql-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <scope>runtime</scope>
        </dependency>

 <!-- druid 连接池-->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid-spring-boot-starter</artifactId>
            <version>1.1.10</version>
        </dependency>

application.yml 配置

spring:
    datasource:
        type: com.alibaba.druid.pool.DruidDataSource
        driverClassName: com.mysql.jdbc.Driver
        druid:
            first:  #数据源1
                url: jdbc:mysql://localhost:3306/operating_unit?useUnicode=true&characterEncoding=utf-8&serverTimezone=GMT%2B8
                username: root
                password: 123456
            second:  #数据源2
                url: jdbc:mysql://localhost:3306/operating_unit?useUnicode=true&characterEncoding=utf-8&serverTimezone=GMT%2B8
                username: root
                password: 123456
            initial-size: 10
            max-active: 100
            min-idle: 10
            max-wait: 60000
            pool-prepared-statements: true
            max-pool-prepared-statement-per-connection-size: 20
            time-between-eviction-runs-millis: 60000
            min-evictable-idle-time-millis: 300000
            validation-query: SELECT 1 FROM DUAL
            test-while-idle: true
            test-on-borrow: false
            test-on-return: false
            stat-view-servlet:
                enabled: true
                url-pattern: /druid/*
                login-username: admin
                login-password: admin
            filter:
                stat:
                    log-slow-sql: true
                    slow-sql-millis: 1000
                    678-sql: true
                wall:
                    config:
                        multi-statement-allow: true

DataSourcesNames (配置数据源名称)

package com.gpdi.operatingunit.datasources;

/**
 * @Description: 多数据源配置
 * @Author: Lxq
 * @Date: 2019/10/18 11:06
 */
public interface DataSourcesNames {

    String FIRST = "first";

    String SECOND = "second";
}

DataSource (自定义注解)

package com.gpdi.operatingunit.datasources.annotation;

import java.lang.annotation.*;

/**
 * @Description: 多数据源注解
 * @Author: Lxq
 * @Date: 2019/10/18 11:10
 */
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface DataSource {
    String name() default "";
}

DataSourceAspect (数据源切面)

package com.gpdi.operatingunit.datasources.aspect;

import com.gpdi.operatingunit.datasources.DataSourcesNames;
import com.gpdi.operatingunit.datasources.DynamicDataSource;
import com.gpdi.operatingunit.datasources.annotation.DataSource;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
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.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.Ordered;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;

/**
 * @Description:
 * @Author: Lxq
 * @Date: 2019/10/18 11:13
 */
@Aspect
@Component
public class DataSourceAspect implements Ordered {

    protected Logger logger = LoggerFactory.getLogger(getClass());

    @Pointcut("@annotation(com.gpdi.operatingunit.datasources.annotation.DataSource)")
    public void dataSourcePointCut() {

    }

    @Around("dataSourcePointCut()")
    public Object around(ProceedingJoinPoint point) throws Throwable {
        MethodSignature signature = (MethodSignature) point.getSignature();
        Method method = signature.getMethod();
        DataSource ds = method.getAnnotation(DataSource.class);
        if (ds == null) {
            DynamicDataSource.setDataSource(DataSourcesNames.FIRST);
            logger.debug("set datasource is " + DataSourcesNames.FIRST);
        } else {
             DynamicDataSource.setDataSource(ds.name());
        }

        try {
            return point.proceed();
        } finally {
            DynamicDataSource.clearDataSource();
            logger.debug("clean datasource");
        }
    }

    @Override
    public int getOrder() {
        return 1;
    }
}

DynamicDataSourceConfig (多数据源配置)

package com.gpdi.operatingunit.datasources;

import com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceBuilder;
import org.springframework.boot.context.properties.ConfigurationProperties;
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;

/**
 * @Description: 多数据源配置
 * @Author: Lxq
 * @Date: 2019/10/18 11:37
 */
@Configuration
public class DynamicDataSourceConfig {

    @Bean
    @ConfigurationProperties("spring.datasource.druid.first")
    public DataSource firstDataSource(){
        return DruidDataSourceBuilder.create().build();
    }


    @Bean
    @ConfigurationProperties("spring.datasource.druid.second")
    public DataSource secondDataSource(){
        return DruidDataSourceBuilder.create().build();
    }


    @Bean
    @Primary
    public DynamicDataSource dataSource(DataSource firstDataSource, DataSource secondDataSource) {
        Map<String, DataSource> targetDataSources = new HashMap<>();
        targetDataSources.put(DataSourcesNames.FIRST, firstDataSource);
        targetDataSources.put(DataSourcesNames.SECOND, secondDataSource);
        return new DynamicDataSource(firstDataSource, targetDataSources);
    }

}

DynamicDataSource (设置数据源)

package com.gpdi.operatingunit.datasources;

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

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

/**
 * @Description: 多数据源配置
 * @Author: Lxq
 * @Date: 2019/10/18 11:22
 */
public class DynamicDataSource extends AbstractRoutingDataSource {

    /**
     * ThreadLocal 用于提供线程局部变量,在多线程环境可以保证各个线程里的变量独立于其它线程里的变量。
     * 也就是说 ThreadLocal 可以为每个线程创建一个【单独的变量副本】,相当于线程的 private static 类型变量。
     */
    private static final ThreadLocal<String> contextHolder = new ThreadLocal<>();

    /**
     * @param dataSource        默认的数据源
     * @param targetDataSources 目标数据源
     */
    public DynamicDataSource(DataSource dataSource, Map<String, DataSource> targetDataSources) {
        super.setDefaultTargetDataSource(dataSource);
        super.setTargetDataSources(new HashMap<>(targetDataSources));
        super.afterPropertiesSet();
    }

    @Override
    protected Object determineCurrentLookupKey() {
        return getDataSource();
    }

    public static void setDataSource(String dataSource) {
        contextHolder.set(dataSource);
    }

    public static String getDataSource() {
        return contextHolder.get();
    }

    public static void clearDataSource() {
        contextHolder.remove();
    }
}

测试

DataSourceTestService

package com.gpdi.operatingunit;

import com.gpdi.operatingunit.datasources.DataSourcesNames;
import com.gpdi.operatingunit.datasources.annotation.DataSource;
import com.gpdi.operatingunit.entity.system.SysUser;
import com.gpdi.operatingunit.service.system.SysUserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

/**
 * @Description:
 * @Author: Lxq
 * @Date: 2019/10/21 10:49
 */
@Service
public class DataSourceTestService {

    @Autowired
    private SysUserService sysUserService;

    public SysUser queryObject(Integer userId){
        return sysUserService.queryUserById(userId);
    }

    @DataSource(name = DataSourcesNames.SECOND)
    public SysUser queryObject2(Integer userId){
        return sysUserService.queryUserById(userId);
    }

}

DynamicDataSourceTest

package com.gpdi.operatingunit;

import com.gpdi.operatingunit.entity.system.SysUser;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

/**
 * @Description:
 * @Author: Lxq
 * @Date: 2019/10/21 10:53
 */
@RunWith(SpringRunner.class)
@SpringBootTest
public class DynamicDataSourceTest {

    @Autowired
    private DataSourceTestService dataSourceTestService;

    @Test
    public void test(){
        //数据源1
        SysUser user = dataSourceTestService.queryObject(1);
        System.out.println(user);

        //数据源2
        SysUser user2 = dataSourceTestService.queryObject2(1);
        System.out.println(user2);

    }
}
发布了43 篇原创文章 · 获赞 27 · 访问量 2891

猜你喜欢

转载自blog.csdn.net/weixin_38982591/article/details/104068420