1.yml多数据源配置
amdb,josdb,josdbqy,分别为自定义数据源名称,type指定数据源使用的连接池。
2.新建类DataSourceProperties用于读取yml文件中的自定义数据源属性
@Component
public class DataSourceProperties {@Value("${spring.datasource.amdb.jdbc-url}")private String amdbUrl;@Value("${spring.datasource.amdb.username}")private String amdbUserName;@Value("${spring.datasource.amdb.password}")private String amdbPassword;@Value("${spring.datasource.amdb.driver-class-name}")private String amdbDriverClass;@Value("${spring.datasource.josdb.jdbc-url}")private String josdbUrl;@Value("${spring.datasource.josdb.username}")private String josdbUserName;@Value("${spring.datasource.josdb.password}")private String josdbPassword;@Value("${spring.datasource.josdb.driver-class-name}")private String josdbDriverClass;@Value("${spring.datasource.josdbqy.jdbc-url}")private String josdbqyUrl;@Value("${spring.datasource.josdbqy.username}")private String josdbqyUserName;@Value("${spring.datasource.josdbqy.password}")private String josdbqyPassword;@Value("${spring.datasource.josdbqy.driver-class-name}")private String josdbqyDriverClass;public String getAmdbUrl() {return amdbUrl;}public void setAmdbUrl(String amdbUrl) {this.amdbUrl = amdbUrl;}public String getAmdbUserName() {return amdbUserName;}public void setAmdbUserName(String amdbUserName) {this.amdbUserName = amdbUserName;}public String getAmdbPassword() {return amdbPassword;}public void setAmdbPassword(String amdbPassword) {this.amdbPassword = amdbPassword;}public String getAmdbDriverClass() {return amdbDriverClass;}public void setAmdbDriverClass(String amdbDriverClass) {this.amdbDriverClass = amdbDriverClass;}public String getJosdbUrl() {return josdbUrl;}public void setJosdbUrl(String josdbUrl) {this.josdbUrl = josdbUrl;}public String getJosdbUserName() {return josdbUserName;}public void setJosdbUserName(String josdbUserName) {this.josdbUserName = josdbUserName;}public String getJosdbPassword() {return josdbPassword;}public void setJosdbPassword(String josdbPassword) {this.josdbPassword = josdbPassword;}public String getJosdbDriverClass() {return josdbDriverClass;}public void setJosdbDriverClass(String josdbDriverClass) {this.josdbDriverClass = josdbDriverClass;}public String getJosdbqyUrl() {return josdbqyUrl;}public void setJosdbqyUrl(String josdbqyUrl) {this.josdbqyUrl = josdbqyUrl;}public String getJosdbqyUserName() {return josdbqyUserName;}public void setJosdbqyUserName(String josdbqyUserName) {this.josdbqyUserName = josdbqyUserName;}public String getJosdbqyPassword() {return josdbqyPassword;}public void setJosdbqyPassword(String josdbqyPassword) {this.josdbqyPassword = josdbqyPassword;}public String getJosdbqyDriverClass() {return josdbqyDriverClass;}public void setJosdbqyDriverClass(String josdbqyDriverClass) {this.josdbqyDriverClass = josdbqyDriverClass;}
}
3.创建类DynamicDataSource继承AbstractRoutingDataSource并实determineCurrentLookupKey()
方法,从DataSourceContextHolder动态获取对应线程的数据源。
public class DynamicDataSource extends AbstractRoutingDataSource {@Overrideprotected Object determineCurrentLookupKey() {return DataSourceContextHolder.getDataSource();}}
4.再创建DataSourceConfig类,创建数据源
@Configuration
public class DataSourceConfig {@AutowiredDataSourceProperties dataSourceProperties;@Bean(name = "amdb")public DataSource amdb() {HikariDataSource amdb = new HikariDataSource();amdb.setJdbcUrl(dataSourceProperties.getAmdbUrl());amdb.setDriverClassName(dataSourceProperties.getAmdbDriverClass());amdb.setUsername(dataSourceProperties.getAmdbUserName());amdb.setPassword(dataSourceProperties.getAmdbPassword());amdb.setPoolName("HikariPool-amdb");amdb.setAutoCommit(true);amdb.setReadOnly(false);amdb.setConnectionTestQuery("SELECT 1;");return amdb;}@Bean(name = "josdb")public DataSource josdb() {HikariDataSource josdb = new HikariDataSource();josdb.setJdbcUrl(dataSourceProperties.getJosdbUrl());josdb.setDriverClassName(dataSourceProperties.getJosdbDriverClass());josdb.setUsername(dataSourceProperties.getJosdbUserName());josdb.setPassword(dataSourceProperties.getJosdbPassword());josdb.setPoolName("HikariPool-josdb");josdb.setAutoCommit(true);josdb.setReadOnly(false);josdb.setConnectionTestQuery("SELECT 1;");return josdb;}@Bean(name = "josdbqy")public DataSource josdbqy() {HikariDataSource josdbqy = new HikariDataSource();josdbqy.setJdbcUrl(dataSourceProperties.getJosdbqyUrl());josdbqy.setDriverClassName(dataSourceProperties.getJosdbqyDriverClass());josdbqy.setUsername(dataSourceProperties.getJosdbqyUserName());josdbqy.setPassword(dataSourceProperties.getJosdbqyPassword());josdbqy.setPoolName("HikariPool-josdbqy");josdbqy.setAutoCommit(true);josdbqy.setReadOnly(false);josdbqy.setConnectionTestQuery("SELECT 1;");return josdbqy;}@Bean(name = "amdbJdbcTemplate")public JdbcTemplate amdbJdbcTemplate(@Qualifier("amdb") DataSource dataSource) {return new JdbcTemplate(dataSource);}@Bean(name = "josdbJdbcTemplate")public JdbcTemplate josdbJdbcTemplate(@Qualifier("josdb") DataSource dataSource) {return new JdbcTemplate(dataSource);}@Bean(name = "josdbqyJdbcTemplate")public JdbcTemplate josdbqyJdbcTemplate(@Qualifier("josdbqy") DataSource dataSource) {return new JdbcTemplate(dataSource);}@Primary@Bean("dynamicDataSource")public DataSource dynamicDataSource() {Map<Object, Object> targetDataSources = new HashMap<>(3);targetDataSources.put(DataSourceTypeEnum.amdb, amdb());targetDataSources.put(DataSourceTypeEnum.josdb, josdb());targetDataSources.put(DataSourceTypeEnum.josdbqy, josdbqy());// 添加数据源名称到列表DataSourceContextHolder.dataSourceIds.add(DataSourceTypeEnum.amdb.name());DataSourceContextHolder.dataSourceIds.add(DataSourceTypeEnum.josdb.name());DataSourceContextHolder.dataSourceIds.add(DataSourceTypeEnum.josdbqy.name());DynamicDataSource dynamicDataSource = new DynamicDataSource();// 如果没有指定数据源自动切换主数据源dynamicDataSource.setDefaultTargetDataSource(amdb());dynamicDataSource.setTargetDataSources(targetDataSources);return dynamicDataSource;}@Beanpublic PlatformTransactionManager transactionManager(EntityManagerFactory entityManagerFactory) {JpaTransactionManager jpaTransactionManager = new JpaTransactionManager(entityManagerFactory);jpaTransactionManager.setDataSource(dynamicDataSource());return jpaTransactionManager;}
创建对应的三个数据源,amdb,josdb,josdbqy,再创建对应的jdbctemplate, 再创建指定数据源的方法dynamicDataSource(),以及最后指定对应的Jpa事务管理器。
5.创建DataSourceContextHolder动态数据源上下文管理
public class DataSourceContextHolder {// 存放当前线程使用的数据源类型private static final ThreadLocal<DataSourceTypeEnum> contextHolder = new ThreadLocal<>();//存放数据源idpublic static List<String> dataSourceIds = new ArrayList<String>();// 设置数据源public static void setDataSource(DataSourceTypeEnum type) {contextHolder.set(type);}// 获取数据源public static DataSourceTypeEnum getDataSource() {return contextHolder.get();}// 清除数据源public static void clearDataSource() {contextHolder.remove();}//判断当前数据源是否存在public static boolean isContainsDataSource(String dataSourceId) {return dataSourceIds.contains(dataSourceId);}
}
6.创建自定义注解DS类
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.METHOD })
public @interface DS {DataSourceTypeEnum value() default DataSourceTypeEnum.amdb;
}
7.使用aop的切面来切换数据源。
@Aspect
@Order(-10) // 保证该AOP在@Transactional之前执行
@Component
public class DynamicDataSourceAspect {private static final Logger logger = LoggerFactory.getLogger(DynamicDataSourceAspect.class);@Before(value = "@annotation(source)")public void changeDataSource(JoinPoint point, DS source) throws Exception {DataSourceTypeEnum currentSource = source.value();logger.info("Change DataSource To:[" + currentSource + "]");DataSourceContextHolder.setDataSource(currentSource);}@After(value = "@annotation(source)")public void restoreDataSource(JoinPoint point, DS source) {// 方法执行完毕之后,销毁当前数据源信息,进行垃圾回收。DataSourceContextHolder.clearDataSource();logger.info("Clear Change DataSource...");}}
8.在service的实现类来使用数据源的切换,在所需方法上加上DS注解以及对应的数据源类型,即可实现数据源切换
9.加上枚举类
public enum DataSourceTypeEnum {amdb, josdb, josdbqy
}