spring boot 注解方式配置多数据源与使用

把学到的知识总结一下,方便以后使用。(毕竟百度了一天了,都没有找到符合自己的[囧])

1、首先看一下application-dev.yml 配置

spring:
    datasource:
        type: com.alibaba.druid.pool.DruidDataSource
        druid:
            first:  #数据源1
                driverClassName: com.mysql.jdbc.Driver
                url: jdbc:mysql://127.0.0.1:3306/xujl?useUnicode=true&characterEncoding=UTF-8
                username: root
                password: admin
            second:  #数据源2
                url: jdbc:postgresql://172.xx.x.xx:xxxx/pcsu?charSet=utf-8
                username: suit_test
                password: suit_test
                driverClassName: org.postgresql.Driver
            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
                    merge-sql: true
                wall:
                    config:
                        multi-statement-allow: true
上面的方式实现就已经配置了两个 数据源了,下面来看下代码的实现

2、配置一个注解,方便使用,直接在需要配置的方法上面加上数据源即可

@Target({ ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface DataSource {
    String name() default "";
}

2-1:配置管理多数据源的名称,方便管理。

/**
 * 增加多数据源,在此配置 
 */
public interface DataSourceNames {
    String FIRST = "first";
    String SECOND = "second"; 
}
3、动态数据源加载

/**
 * 动态数据源 
 */
public class DynamicDataSource extends AbstractRoutingDataSource {
    //用来保存数据源与获取数据源
    private static final ThreadLocal<String> contextHolder = new ThreadLocal<String>();

    public DynamicDataSource(DataSource defaultTargetDataSource, Map<String, DataSource> targetDataSources) {
        super.setDefaultTargetDataSource(defaultTargetDataSource);
        super.setTargetDataSources(new HashMap<Object, Object>(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();
    }

}
这里有必要说一下AbstractRoutingDataSource这个类,加载一个图片:


可以看到AbstractRoutingDataSource获取数据源之前会先调用determineCurrentLookupKey方法查找当前的lookupKey,这个lookupKey就是数据源标识。
因此通过重写这个查找数据源标识的方法就可以让spring切换到指定的数据源了。

(这张图片出自:点击打开链接 尊重原创。)

3-1:重要一点:吧上面的信心加载到配置中

/**
 * 配置多数据源 
 */
@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(DataSourceNames.FIRST, firstDataSource);
        targetDataSources.put(DataSourceNames.SECOND, secondDataSource);
        return new DynamicDataSource(firstDataSource, targetDataSources);
    }
}
4、最最重要的一步,就是使用spring的aop原理,切面方式加载数据源

/**
 * 多数据源,切面处理类 处理带有注解的方法类
 */
@Aspect
@Component
public class DataSourceAspect implements Ordered {

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

	@Pointcut("@annotation(xxxx.DataSource)")//注意:这里的xxxx代表的是上面public @interface DataSource这个注解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(DataSourceNames.FIRST);
			logger.debug("set datasource is " + DataSourceNames.FIRST);
		} else {
			DynamicDataSource.setDataSource(ds.name());
			logger.debug("set datasource is " + ds.name());
		}
		try {
			return point.proceed();
		} finally {
			DynamicDataSource.clearDataSource();
			logger.debug("clean datasource");
		}
	}



	@Override
	public int getOrder() {
		return 1;
	}
}
5、最后一步就是使用了在你的service的实现类 serviceImpl上面进行注解,这里是重点(我刚开一直放在dao上面,因为我用的是mybatis,以为就是要放在这个上面,结果一直出不来,最后才知道应该放在serviceImpl上面)

	@Override
	@DataSource(name="second")
	public List<IntegralExchangeRule> list(Map<String,Object> map) {
		return dao.list(map);
	}
OK,现在已经全部配置完成,可以使用了

有必要说一下:我上面的DataSourceAspect这个类里面around方法里面,已经默认是数据源1,如果你不配置@DaeSource(name=""),它默认会使用第一个数据源,否则的话,按照你的数据源名称去使用的。








  • 2
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 16
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值