项目git地址:Jacob-dynamic

准备工作

# 创建数据库db1
CREATE DATABASE `db1`CHARACTER SET utf8 COLLATE utf8_bin
# 创建user表
CREATE TABLE `user` (`id` int(11) DEFAULT NULL,`name` varchar(255) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8
# 添加数据
INSERT INTO `db1`.`user` (`id`, `name`) VALUES (1, 'db1_1'); 
INSERT INTO `db1`.`user` (`id`, `name`) VALUES (2, 'db1_2'); 
INSERT INTO `db1`.`user` (`id`, `name`) VALUES (3, 'db1_3'); 
INSERT INTO `db1`.`user` (`id`, `name`) VALUES (4, 'db1_4'); 
INSERT INTO `db1`.`user` (`id`, `name`) VALUES (5, 'db1_5'); # 创建数据库db2
CREATE DATABASE `db2`CHARACTER SET utf8 COLLATE utf8_bin
# 创建user表
CREATE TABLE `user` (`id` int(11) DEFAULT NULL,`name` varchar(255) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8
# 添加数据
INSERT INTO `db2`.`user` (`id`, `name`) VALUES (1, 'db2_1'); 
INSERT INTO `db2`.`user` (`id`, `name`) VALUES (2, 'db2_2'); 
INSERT INTO `db2`.`user` (`id`, `name`) VALUES (3, 'db2_3'); 
INSERT INTO `db2`.`user` (`id`, `name`) VALUES (4, 'db2_4'); 
INSERT INTO `db2`.`user` (`id`, `name`) VALUES (5, 'db2_5');

创建项目

最终目录结果

image-20200814155826016

添加依赖

<!-- mysql start --><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><scope>runtime</scope></dependency><!-- mysql end --><!-- web start --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><!-- web end --><!-- lombok start  --><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><optional>true</optional></dependency><!-- lombok end --><!-- hutool start --><dependency><groupId>cn.hutool</groupId><artifactId>hutool-all</artifactId><version>${hutool.versiont}</version></dependency><!-- hutool end --><!-- configuration start --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-configuration-processor</artifactId><optional>true</optional></dependency><!-- configuration end --><!-- swagger start --><dependency><groupId>io.springfox</groupId><artifactId>springfox-swagger2</artifactId><version>2.9.2</version></dependency><dependency><groupId>com.github.xiaoymin</groupId><artifactId>swagger-bootstrap-ui</artifactId><version>1.9.6</version></dependency><!-- swagger end --><!-- mybatis-plus start --><dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId><version>3.1.0</version></dependency><!-- mybatis-plus end --><!-- spring aop start --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-aop</artifactId></dependency><!-- spring aop end -->

添加配置

server:port: 8085spring:datasource:db1:type: com.zaxxer.hikari.HikariDataSourcedriver-class-name: com.mysql.cj.jdbc.Driverusername: rootpassword: 123456hikari:maximum-pool-size: 20minimum-idle: 2url: jdbc:mysql://localhost:3306/springbootdb?characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=Asia/Shanghaidb2:type: com.zaxxer.hikari.HikariDataSourcedriver-class-name: com.mysql.cj.jdbc.Driverusername: rootpassword: 123456hikari:maximum-pool-size: 20minimum-idle: 2url: jdbc:mysql://localhost:3306/springbootdb2?characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=Asia/Shanghai

定义枚举

package cn.org.jacob.enums;
//...
public enum DataSourceTypeEnum {DB1,DB2
}

编写aop

package cn.org.jacob.aop;
//...
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
public @interface DataSource {DataSourceTypeEnum value() default DataSourceTypeEnum.DB1;}
package cn.org.jacob.aop;
//...
@Slf4j
@Aspect
@Component
@Order(-1)
public class DataSourceAspect {@Pointcut("@annotation(cn.org.jacob.aop.DataSource)")public void dataSourceAspectMethod() {}@Before(value = "dataSourceAspectMethod()")public void beforeDataSource(JoinPoint joinPoint) {
//        log.info("进入切点>>>>>>>>>>>>>>>>>>>>>>>>>>>执行切换数据源");MethodSignature signature = (MethodSignature) joinPoint.getSignature();DataSource annotation = signature.getMethod().getAnnotation(DataSource.class);DataSourceTypeEnum value = annotation.value();DataSourceContextHolder.setDataSource(value);log.info("当前使用的数据源:{}", value);}@After("dataSourceAspectMethod()")public void afterDataSource() {DataSourceContextHolder.clear();}
}
package cn.org.jacob.aop;
//...
public class DataSourceContextHolder {/*** 吧数据源存放当前线程*/private static final ThreadLocal<DataSourceTypeEnum> contextHolder = new ThreadLocal<>();/*** 设置数据源** @param dataSource 当前的数据源*/public static void setDataSource(DataSourceTypeEnum dataSource) {contextHolder.set(dataSource);}/*** 获取数据源** @return 当前数据源*/public static DataSourceTypeEnum getDataSource() {return contextHolder.get();}/*** 删除当前线程上下文的数据源信息*/public static void clear() {contextHolder.remove();}}

编写配置

package cn.org.jacob.config;
//..
@Configuration
@EnableSwagger2
public class SwaggerConfiguration {@Beanpublic Docket createRestApi() {return new Docket(DocumentationType.SWAGGER_2).apiInfo(apiInfo()).select().apis(RequestHandlerSelectors.basePackage("cn.org.jacob")).paths(PathSelectors.any()).build();}private ApiInfo apiInfo() {return new ApiInfoBuilder().title("swagger-bootstrap-ui RESTful APIs").description("swagger-bootstrap-ui").termsOfServiceUrl("http://localhost:8081/").contact("m15870979735@163.com").version("1.0").build();}
}
package cn.org.jacob.config;
//..
@Data
@Component
@ConfigurationProperties(prefix = "spring.datasource.db1")
public class Db1Config {private String driverClassName;private String userName;private String password;private String url;}
package cn.org.jacob.config;
//..
@Data
@Component
@ConfigurationProperties(prefix = "spring.datasource.db2")
public class Db2Config {private String driverClassName;private String userName;private String password;private String url;
}
@Slf4j
public class DynamicDataSource extends AbstractRoutingDataSource {@Overrideprotected Object determineCurrentLookupKey() {return DataSourceContextHolder.getDataSource();}
}
package cn.org.jacob.config;
//..
@Configuration
@MapperScan("cn.org.jacob.mapper")
@Slf4j
public class MybatisPlusConfigurer {@AutowiredDb1Config db1Config;@AutowiredDb2Config db2Config;/*** 分页插件** @return PaginationInterceptor*/@Beanpublic PaginationInterceptor paginationInterceptor() {return new PaginationInterceptor();}@Primary@Bean(value = "db1DataSource")public DataSource roadDataSource() {return DataSourceBuilder.create().url(db1Config.getUrl()).driverClassName(db1Config.getDriverClassName()).username(db1Config.getUserName()).password(db1Config.getPassword()).type(HikariDataSource.class).build();}@Bean(value = "db2DataSource")public DataSource garageDataSource() {return DataSourceBuilder.create().url(db2Config.getUrl()).driverClassName(db2Config.getDriverClassName()).username(db2Config.getUserName()).password(db2Config.getPassword()).type(HikariDataSource.class).build();}@Beanpublic DynamicDataSource dataSource(@Qualifier("db1DataSource") DataSource db1DataSource,@Qualifier("db2DataSource") DataSource db2DataSource) {Map<Object, Object> map = new HashMap<>(2);map.put(DataSourceTypeEnum.DB1, db1DataSource);map.put(DataSourceTypeEnum.DB2, db2DataSource);DynamicDataSource dynamicDataSource = new DynamicDataSource();dynamicDataSource.setTargetDataSources(map);dynamicDataSource.setDefaultTargetDataSource(db1DataSource);return dynamicDataSource;}@Beanpublic MybatisSqlSessionFactoryBean sqlSessionFactoryBean() throws Exception {MybatisSqlSessionFactoryBean sqlSessionFactoryBean = new MybatisSqlSessionFactoryBean();// 重新设置数据源 DB1,DB2 两个sqlSessionFactoryBean.setDataSource(dataSource(roadDataSource(), garageDataSource()));Resource[] resources = new PathMatchingResourcePatternResolver().getResources("classpath:mapper/*.xml");sqlSessionFactoryBean.setMapperLocations(resources);// 手动设置分页插件sqlSessionFactoryBean.setPlugins(new Interceptor[] { paginationInterceptor() });return sqlSessionFactoryBean;}@Beanpublic PlatformTransactionManager transactionManager(DynamicDataSource dynamicDataSource) {return new DataSourceTransactionManager(dynamicDataSource);}
}

实体类,Mapper,service忽略

编写控制器

@RestController
@Slf4j
@Api(value = "用户", tags = {"用户"})
@AllArgsConstructor
@RequestMapping("user")
public class UserController {private UserService userService;@GetMapping("db1List")@ApiOperation(value = "获取db1List")@DataSource(DataSourceTypeEnum.DB1)public List<User> db1List(){return userService.list();}@GetMapping("db2List")@ApiOperation(value = "获取db2List")@DataSource(DataSourceTypeEnum.DB2)public List<User> db2List(){return userService.list();}}

访问查看效果

image-20200814160526575

image-20200814160608915