介绍
自定义 DynamicDataSource 继承 AbstractRoutingDataSource,重写 determineCurrentLookupKey()获取数据源 key 值实现数据源的切换。
DynamicDataSource
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53
| package com.why.datasource;
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
import javax.sql.DataSource; import java.util.Map;
public class DynamicDataSource extends AbstractRoutingDataSource {
private static final ThreadLocal<String> CONTEXT_HOLDER = new ThreadLocal<>();
public DynamicDataSource(DataSource defaultTargetDataSource, Map<Object, Object> targetDataSources) { super.setDefaultTargetDataSource(defaultTargetDataSource); super.setTargetDataSources(targetDataSources); super.afterPropertiesSet(); }
@Override protected Object determineCurrentLookupKey() { return getDataSource(); }
public static void setDataSource(String dataSource) { CONTEXT_HOLDER.set(dataSource); }
public static String getDataSource() { return CONTEXT_HOLDER.get(); }
public static void clearDataSource() { CONTEXT_HOLDER.remove(); }
}
|
DynamicDataSourceConfig 配置数据源
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44
| package com.why.datasource;
import com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceBuilder; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; 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;
@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(@Qualifier("firstDataSource") DataSource firstDataSource1, @Qualifier("secondDataSource") DataSource secondDataSource1) { Map<Object, Object> targetDataSources = new HashMap<>(5); targetDataSources.put(DataSourceNames.FIRST, firstDataSource1); targetDataSources.put(DataSourceNames.SECOND, secondDataSource1); return new DynamicDataSource(firstDataSource1, targetDataSources); }
}
|
CurDataSource 注解类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| package com.why.datasource;
import java.lang.annotation.*;
@Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface CurDataSource {
String name() default "";
}
|
AbstractRoutingDataSource 核心方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
| @Override public void afterPropertiesSet() { if (this.targetDataSources == null) { throw new IllegalArgumentException("Property 'targetDataSources' is required"); } this.resolvedDataSources = new HashMap<>(this.targetDataSources.size()); this.targetDataSources.forEach((key, value) -> { Object lookupKey = resolveSpecifiedLookupKey(key); DataSource dataSource = resolveSpecifiedDataSource(value); this.resolvedDataSources.put(lookupKey, dataSource); }); if (this.defaultTargetDataSource != null) { this.resolvedDefaultDataSource = resolveSpecifiedDataSource(this.defaultTargetDataSource); } }
@Override public Connection getConnection() throws SQLException { return determineTargetDataSource().getConnection(); }
protected DataSource determineTargetDataSource() { Assert.notNull(this.resolvedDataSources, "DataSource router not initialized"); Object lookupKey = determineCurrentLookupKey(); DataSource dataSource = this.resolvedDataSources.get(lookupKey); if (dataSource == null && (this.lenientFallback || lookupKey == null)) { dataSource = this.resolvedDefaultDataSource; } if (dataSource == null) { throw new IllegalStateException("Cannot determine target DataSource for lookup key [" + lookupKey + "]"); } return dataSource; }
|
