SpringBoot+Hirika 实现动态数据源

1 篇文章 0 订阅
1 篇文章 0 订阅

1、实现原理

AbstractRoutingDataSource中,determineTargetDataSource 方法通过数据源的标识获取当前数据源;determineCurrentLookupKey方法则是获取数据源标识,实现动态切换数据源,需要实现determineCurrentLookupKey方法,动态提供数据源标识即可。这边使用AOP识别方法上的注解进行数据源切换。没用注解使用默认数据源。

2、需要的类

实现AbstractRoutingDataSource的方法,使用DataSourceContextHolder统一数据源管理
DynamicDataSource
package com.hsshy.beam.common.mutidatasource;

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

/**
 * 动态数据源
 *
 * @author hs
 * @date 2019年2月12日
 */
public class DynamicDataSource extends AbstractRoutingDataSource {

	@Override
	protected Object determineCurrentLookupKey() {
		return DataSourceContextHolder.getDataSourceType();
	}

}

DataSourceContextHolder
package com.hsshy.beam.common.mutidatasource;

/**
 * datasource的上下文
 *
 * @author hs
 * @date 2019年2月12日
 */
public class DataSourceContextHolder {

    private static final ThreadLocal<String> contextHolder = new ThreadLocal<String>();

    /**
     * 设置数据源类型
     *
     * @param dataSourceType 数据库类型
     */
    public static void setDataSourceType(String dataSourceType) {
        contextHolder.set(dataSourceType);
    }

    /**
     * 获取数据源类型
     */
    public static String getDataSourceType() {
        return contextHolder.get();
    }

    /**
     * 清除数据源类型
     */
    public static void clearDataSourceType() {
        contextHolder.remove();
    }
}

数据库数据源配置
a、默认数据源 HikariProperties配置
package com.hsshy.beam.common.config;


import com.zaxxer.hikari.HikariDataSource;

/**
 * <p>数据库数据源配置</p>
 * @author hs
 * @date 2019年2月12日
 */
public class HikariProperties {

    private String url = "jdbc:mysql://127.0.0.1:3306/beam?autoReconnect=true&useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull";

    private String username = "root";

    private String password = "root";

    private String driverClassName = "com.mysql.cj.jdbc.Driver";

    private long connectionTimeout = 60000L;

    private long idleTimeout = 60000L;

    private long validationTimeout = 3000L;

    private long maxLifetime = 60000L;

    private int maximumPoolSize = 60;

    private int minimumIdle = 10;

    public void config(HikariDataSource dataSource) {

        dataSource.setJdbcUrl(url);
        dataSource.setUsername(username);
        dataSource.setPassword(password);
        dataSource.setDriverClassName(driverClassName);
        dataSource.setDriverClassName(driverClassName);
        dataSource.setConnectionTimeout(connectionTimeout);
        dataSource.setIdleTimeout(idleTimeout);
        dataSource.setValidationTimeout(validationTimeout);
        dataSource.setMaxLifetime(maxLifetime);
        dataSource.setMaximumPoolSize(maximumPoolSize);
        dataSource.setMinimumIdle(minimumIdle);
        dataSource.setReadOnly(false);

    }

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

    public String getDriverClassName() {
        return driverClassName;
    }

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

    public long getConnectionTimeout() {
        return connectionTimeout;
    }

    public void setConnectionTimeout(long connectionTimeout) {
        this.connectionTimeout = connectionTimeout;
    }

    public long getIdleTimeout() {
        return idleTimeout;
    }

    public void setIdleTimeout(long idleTimeout) {
        this.idleTimeout = idleTimeout;
    }

    public long getValidationTimeout() {
        return validationTimeout;
    }

    public void setValidationTimeout(long validationTimeout) {
        this.validationTimeout = validationTimeout;
    }

    public long getMaxLifetime() {
        return maxLifetime;
    }

    public void setMaxLifetime(long maxLifetime) {
        this.maxLifetime = maxLifetime;
    }

    public int getMaximumPoolSize() {
        return maximumPoolSize;
    }

    public void setMaximumPoolSize(int maximumPoolSize) {
        this.maximumPoolSize = maximumPoolSize;
    }

    public int getMinimumIdle() {
        return minimumIdle;
    }

    public void setMinimumIdle(int minimumIdle) {
        this.minimumIdle = minimumIdle;
    }
}

b、第二个数据源配置 MutiDataSourceProperties
package com.hsshy.beam.common.config;
import com.zaxxer.hikari.HikariDataSource;

/**
 * 默认多数据源配置
 *
 * @author fengshuonan
 * @date 2017-08-16 10:02
 */
public class MutiDataSourceProperties {

    private String url = "jdbc:mysql://127.0.0.1:3306/biz?autoReconnect=true&useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull";

    private String username = "root";

    private String password = "root";

    private long connectionTimeout = 60000L;

    private long idleTimeout = 60000L;

    private long validationTimeout = 3000L;

    private long maxLifetime = 60000L;

    private int maximumPoolSize = 60;

    private int minimumIdle = 10;

    private String filters = "log4j,wall,mergeStat";

    private String driverClassName = "com.mysql.cj.jdbc.Driver";

    private String[] dataSourceNames = {"dataSourceBeam", "dataSourceBiz"};

    public void config(HikariDataSource dataSource) {
        dataSource.setJdbcUrl(url);
        dataSource.setUsername(username);
        dataSource.setPassword(password);
        dataSource.setDriverClassName(driverClassName);
        dataSource.setConnectionTimeout(connectionTimeout);
        dataSource.setIdleTimeout(idleTimeout);
        dataSource.setValidationTimeout(validationTimeout);
        dataSource.setMaxLifetime(maxLifetime);
        dataSource.setMaximumPoolSize(maximumPoolSize);
        dataSource.setMinimumIdle(minimumIdle);
        dataSource.setReadOnly(false);


    }


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

    public long getConnectionTimeout() {
        return connectionTimeout;
    }

    public void setConnectionTimeout(long connectionTimeout) {
        this.connectionTimeout = connectionTimeout;
    }

    public long getIdleTimeout() {
        return idleTimeout;
    }

    public void setIdleTimeout(long idleTimeout) {
        this.idleTimeout = idleTimeout;
    }

    public long getValidationTimeout() {
        return validationTimeout;
    }

    public void setValidationTimeout(long validationTimeout) {
        this.validationTimeout = validationTimeout;
    }

    public long getMaxLifetime() {
        return maxLifetime;
    }

    public void setMaxLifetime(long maxLifetime) {
        this.maxLifetime = maxLifetime;
    }

    public int getMaximumPoolSize() {
        return maximumPoolSize;
    }

    public void setMaximumPoolSize(int maximumPoolSize) {
        this.maximumPoolSize = maximumPoolSize;
    }

    public int getMinimumIdle() {
        return minimumIdle;
    }

    public void setMinimumIdle(int minimumIdle) {
        this.minimumIdle = minimumIdle;
    }

    public String getDriverClassName() {
        return driverClassName;
    }

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

    public String getFilters() {
        return filters;
    }

    public void setFilters(String filters) {
        this.filters = filters;
    }

    public String[] getDataSourceNames() {
        return dataSourceNames;
    }

    public void setDataSourceNames(String[] dataSourceNames) {
        this.dataSourceNames = dataSourceNames;
    }
}

多数据源配置 MultiDataSourceConfig
package com.hsshy.beam.common.config;
import com.hsshy.beam.common.mutidatasource.DynamicDataSource;
import com.hsshy.beam.common.mutidatasource.aop.MultiSourceExAop;
import com.zaxxer.hikari.HikariDataSource;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.transaction.annotation.EnableTransactionManagement;

import java.sql.SQLException;
import java.util.HashMap;

/**
 * 多数据源配置<br/>
 * <p>
 * 注:由于引入多数据源,所以让spring事务的aop要在多数据源切换aop的后面
 *
 * @author hs
 * @Date 2019/2/12 21:58
 */
@Configuration
@ConditionalOnProperty(prefix = "beam.muti-datasource", name = "open", havingValue = "true")
@EnableTransactionManagement(order = 2)
public class MultiDataSourceConfig {

    @Bean
    @ConfigurationProperties(prefix = "beam.muti-datasource")
    public MutiDataSourceProperties mutiDataSourceProperties() {
        return new MutiDataSourceProperties();
    }

    @Bean
    @ConfigurationProperties(prefix = "spring.datasource")
    public HikariProperties hikariProperties() {
        return new HikariProperties();
    }

    @Bean
    public MultiSourceExAop multiSourceExAop() {
        return new MultiSourceExAop();
    }

    /**
     * guns的数据源
     */
    private HikariDataSource dataSource(HikariProperties druidProperties) {
        HikariDataSource dataSource = new HikariDataSource();
        druidProperties.config(dataSource);
        return dataSource;
    }

    /**
     * 多数据源,第二个数据源
     */
    private HikariDataSource bizDataSource(HikariProperties druidProperties, MutiDataSourceProperties mutiDataSourceProperties) {
        HikariDataSource dataSource = new HikariDataSource();
        druidProperties.config(dataSource);
        mutiDataSourceProperties.config(dataSource);
        return dataSource;
    }

    /**
     * 多数据源连接池配置
     */
    @Bean
    public DynamicDataSource mutiDataSource(HikariProperties druidProperties, MutiDataSourceProperties mutiDataSourceProperties) {

        HikariDataSource dataSourceBeam = dataSource(druidProperties);
        HikariDataSource bizDataSource = bizDataSource(druidProperties, mutiDataSourceProperties);

        try {
            dataSourceBeam.getConnection();
            bizDataSource.getConnection();
        } catch (SQLException sql) {
            sql.printStackTrace();
        }

        DynamicDataSource dynamicDataSource = new DynamicDataSource();
        HashMap<Object, Object> hashMap = new HashMap<>();
        hashMap.put(mutiDataSourceProperties.getDataSourceNames()[0], dataSourceBeam);
        hashMap.put(mutiDataSourceProperties.getDataSourceNames()[1], bizDataSource);
        dynamicDataSource.setTargetDataSources(hashMap);
        dynamicDataSource.setDefaultTargetDataSource(dataSourceBeam);
        return dynamicDataSource;
    }


}
数据源标识 DataSource
package com.hsshy.beam.common.mutidatasource.annotion;

import java.lang.annotation.*;

/**
 * 
 * 多数据源标识
 *
 * @author hs
 * @date 2019年2月12日
 */
@Inherited
@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.METHOD })
public @interface DataSource {

	String name() default "";
}

AOP动态切换数据源 MultiSourceExAop
package com.hsshy.beam.common.mutidatasource.aop;
import com.hsshy.beam.common.config.MutiDataSourceProperties;
import com.hsshy.beam.common.mutidatasource.DataSourceContextHolder;
import com.hsshy.beam.common.mutidatasource.annotion.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.beans.factory.annotation.Autowired;
import org.springframework.core.Ordered;
import java.lang.reflect.Method;

/**
 * 多数据源切换的aop
 *
 * @author hs
 * @date 2019年2月12日
 */
@Aspect
public class MultiSourceExAop implements Ordered {

    private Logger log = LoggerFactory.getLogger(this.getClass());

    @Autowired
    MutiDataSourceProperties mutiDataSourceProperties;

    @Pointcut(value = "@annotation(com.hsshy.beam.common.mutidatasource.annotion.DataSource)")
    private void cut() {

    }

    @Around("cut()")
    public Object around(ProceedingJoinPoint point) throws Throwable {

        Signature signature = point.getSignature();
        MethodSignature methodSignature = null;
        if (!(signature instanceof MethodSignature)) {
            throw new IllegalArgumentException("该注解只能用于方法");
        }
        methodSignature = (MethodSignature) signature;

        Object target = point.getTarget();
        Method currentMethod = target.getClass().getMethod(methodSignature.getName(), methodSignature.getParameterTypes());

        DataSource datasource = currentMethod.getAnnotation(DataSource.class);
        if (datasource != null) {
            DataSourceContextHolder.setDataSourceType(datasource.name());
            log.debug("设置数据源为:" + datasource.name());
        } else {
            DataSourceContextHolder.setDataSourceType(mutiDataSourceProperties.getDataSourceNames()[0]);
            log.debug("设置数据源为:dataSourceCurrent");
        }

        try {
            return point.proceed();
        } finally {
            log.debug("清空数据源信息!");
            DataSourceContextHolder.clearDataSourceType();
        }
    }


    /**
     * aop的顺序要早于spring的事务
     */
    @Override
    public int getOrder() {
        return 1;
    }

}
多数据源枚举 DatasourceEnum
package com.hsshy.beam.common.constant;

/**
 * 
 * 多数据源的枚举
 *
 * @author hs
 * @date 2019年2月12日
 */
public interface DatasourceEnum {

	String DATA_SOURCE_GUNS = "dataSourceBeam";			//beam数据源
	
	String DATA_SOURCE_BIZ = "dataSourceBiz";			//其他业务的数据源
}

配置文件 application.yml
server:
   port: 8081
spring:
  profiles: local
  datasource:
      url: jdbc:mysql://127.0.0.1:3306/beam?autoReconnect=true&useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=CONVERT_TO_NULL&useSSL=false&serverTimezone=GMT%2B8
      username: root
      password: 123456
      filters: log4j,wall,mergeStat
      hikari:
        readOnly: false
        connectionTimeout: 60000
        idleTimeout: 60000
        validationTimeout: 3000
        maxLifetime: 60000
        loginTimeout: 5
        maximumPoolSize: 60
        minimumIdle: 10
  redis:
    database: 0
    host: 127.0.0.1
    port: 6379
    password:      # 密码(默认为空)
    timeout: 6000ms  # 连接超时时长(毫秒)

##多数据源情况的配置
beam:
  muti-datasource:
    open: true
    url: jdbc:mysql://127.0.0.1:3306/test?autoReconnect=true&useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=CONVERT_TO_NULL&useSSL=false&serverTimezone=GMT%2B8
    username: root
    password: 123456
    dataSourceNames:
      - dataSourceBeam
      - dataSourceBiz

只有一个数据源可以使用以下配置,即可使用Hikari数据库连接池

spring:
  profiles: local
  datasource:
      url: jdbc:mysql://127.0.0.1:3306/beam?autoReconnect=true&useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=CONVERT_TO_NULL&useSSL=false&serverTimezone=GMT%2B8
      username: root
      password: root
      filters: log4j,wall,mergeStat
      hikari:
        readOnly: false
        connectionTimeout: 60000
        idleTimeout: 60000
        validationTimeout: 3000
        maxLifetime: 60000
        loginTimeout: 5
        maximumPoolSize: 60
        minimumIdle: 10
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
在Spring Boot中使用DBCP2实现数据源配置可以通过以下步骤进行: 步骤1:添加依赖 在`pom.xml`文件中添加Apache DBCP2的依赖: ```xml <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-dbcp2</artifactId> <version>2.8.0</version> </dependency> ``` 步骤2:配置数据源 在`application.properties`或`application.yml`文件中配置多个数据源的连接信息。例如,配置两个数据源的示例: ```properties # 第一个数据源 spring.datasource.url=jdbc:mysql://localhost:3306/db1 spring.datasource.username=username1 spring.datasource.password=password1 # 第二个数据源 spring.datasource.second.url=jdbc:mysql://localhost:3306/db2 spring.datasource.second.username=username2 spring.datasource.second.password=password2 ``` 步骤3:创建数据源配置类 创建一个数据源配置类,用于创建和管理多个数据源。可以使用`@Configuration`注解来标记这个类,并使用`@Bean`注解来创建不同的数据源。 ```java @Configuration public class DataSourceConfig { @Primary @Bean(name = "dataSource") @ConfigurationProperties(prefix = "spring.datasource") public DataSource primaryDataSource() { return DataSourceBuilder.create().build(); } @Bean(name = "secondDataSource") @ConfigurationProperties(prefix = "spring.datasource.second") public DataSource secondDataSource() { return DataSourceBuilder.create().build(); } } ``` 步骤4:配置数据源交给Spring管理 在`@SpringBootApplication`注解的启动类上添加`@Import`注解,将数据源配置类引入到Spring Boot中: ```java @SpringBootApplication @Import(DataSourceConfig.class) public class YourApplication { // 程序入口 } ``` 步骤5:使用数据源 在需要使用数据源的地方,可以使用`@Qualifier`注解来指定具体使用哪个数据源。 ```java @Service public class YourService { @Autowired @Qualifier("dataSource") private DataSource dataSource; // 其他业务逻辑方法 } ``` 这样就可以通过DBCP2实现数据源的配置和使用了。请根据你的实际情况进行相应的调整和修改。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值