支持RedisTemplate、Redisson、Zookeeper 简单可靠的分布式锁 快速启动器。
+
+# 常见问题
+
+1. 多个库的事物如何处理?
+
+**不能 不能 不能**,一个业务操作涉及多个库不要加事物。
+
+2. 是否支持JPA?
+
+不完全支持,受限于JPA底层,你只能在一个controller下切换第一个库,第二个库不能切换。(如有解决办法请联系作者)
diff --git a/license.txt b/license.txt
new file mode 100644
index 0000000..8470bb2
--- /dev/null
+++ b/license.txt
@@ -0,0 +1,14 @@
+Copyright © ${project.inceptionYear} organization baomidou
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
\ No newline at end of file
diff --git a/pom.xml b/pom.xml
new file mode 100644
index 0000000..55f1729
--- /dev/null
+++ b/pom.xml
@@ -0,0 +1,210 @@
+
+
+ 4.0.0
+
+
+ org.springframework.boot
+ spring-boot-starter-parent
+ 1.5.1.RELEASE
+
+
+
+ com.baomidou
+ dynamic-datasource-spring-boot-starter
+ 2.4.0
+ jar
+
+ dynamic-datasource-spring-boot-starter
+ dynamic datasource with annotation
+ 2018
+
+
+
+ Apache License, Version 2.0
+ http://www.apache.org/licenses/LICENSE-2.0
+
+
+
+
+ baomidou
+ https://gitee.com/baomidou
+
+
+
+
+ TaoYu
+ tracy5546@gmail.com
+
+
+ KanYuXia
+ kanyuxia@outlook.com
+
+
+
+
+ https://github.com/baomidou/dynamic-datasource-spring-boot-starter
+ scm:git:https://github.com/baomidou/dynamic-datasource-spring-boot-starter.git
+ scm:git:https://github.com/baomidou/dynamic-datasource-spring-boot-starter.git
+
+ HEAD
+
+
+
+ UTF-8
+ UTF-8
+ 1.7
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter-jdbc
+
+
+ org.springframework.boot
+ spring-boot-starter-aop
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+ true
+
+
+ com.alibaba
+ druid-spring-boot-starter
+ 1.1.10
+ true
+
+
+ com.baomidou
+ mybatis-plus-boot-starter
+ 3.0.5
+ true
+
+
+ com.zaxxer
+ HikariCP
+ 2.7.0
+ true
+
+
+ org.springframework.boot
+ spring-boot-configuration-processor
+ true
+
+
+ org.projectlombok
+ lombok
+ true
+
+
+ p6spy
+ p6spy
+ 3.8.0
+ true
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+ 3.8.0
+
+ ${java.version}
+ ${java.version}
+
+
+
+ com.mycila
+ license-maven-plugin
+ 3.0
+
+ ${project.basedir}/license.txt
+
+ src/main/java/**
+
+
+
+
+
+ check
+
+
+
+
+
+
+
+
+
+ release
+
+
+ ossrh
+ https://oss.sonatype.org/content/repositories/snapshots
+
+
+ ossrh
+ https://oss.sonatype.org/service/local/staging/deploy/maven2/
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-javadoc-plugin
+
+
+ attach-javadocs
+
+ jar
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-source-plugin
+
+
+ package
+
+ jar-no-fork
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-gpg-plugin
+ 1.6
+
+
+ sign-artifacts
+ verify
+
+ sign
+
+
+
+
+
+ org.sonatype.plugins
+ nexus-staging-maven-plugin
+ 1.6.8
+ true
+
+ ossrh
+ https://oss.sonatype.org/
+ true
+
+
+
+
+
+
+
+
diff --git a/samples/.gitignore b/samples/.gitignore
new file mode 100644
index 0000000..19240d3
--- /dev/null
+++ b/samples/.gitignore
@@ -0,0 +1,25 @@
+*/target/
+!.mvn/wrapper/maven-wrapper.jar
+
+### STS ###
+.apt_generated
+.classpath
+.factorypath
+.project
+.settings
+.springBeans
+.sts4-cache
+
+### IntelliJ IDEA ###
+.idea
+*.iws
+*.iml
+*.ipr
+
+### NetBeans ###
+/nbproject/private/
+/build/
+/nbbuild/
+/dist/
+/nbdist/
+/.nb-gradle/
\ No newline at end of file
diff --git a/samples/README.md b/samples/README.md
new file mode 100644
index 0000000..89db2a2
--- /dev/null
+++ b/samples/README.md
@@ -0,0 +1,13 @@
+# 演示例子
+
+所有数据库连接为h2数据库,仅供测试。
+
+所有测试可直接跑,注意启动的日志。
+
+1. dynamic-jdbc-template-sample 原生jdbcTemplate下使用的示范
+2. dynamic-mybatis-sample 原生mybatis下使用的示范
+3. dynamic-mybatisplus2-sample mybatisPlus2下使用的示范
+4. dynamic-mybatisplus3-sample mybatisPlus3下使用的示范
+5. dynamic-druid-mybatis-sample mybatis和druid下使用的示范
+6. dynamic-spel-sample mybatis和从参数获取数据源下使用的示范(高级)适用于多租户
+7. dynamic-nest-sample 嵌套切换示范
\ No newline at end of file
diff --git a/samples/dynamic-druid-mybatis-sample/pom.xml b/samples/dynamic-druid-mybatis-sample/pom.xml
new file mode 100644
index 0000000..528d313
--- /dev/null
+++ b/samples/dynamic-druid-mybatis-sample/pom.xml
@@ -0,0 +1,31 @@
+
+
+
+ dynamic-datsource-samples
+ com.baomidou
+ 1.0.0
+
+ 4.0.0
+
+ dynamic-druid-mybatis-sample
+
+
+
+ org.mybatis.spring.boot
+ mybatis-spring-boot-starter
+ 1.3.2
+
+
+ com.alibaba
+ druid-spring-boot-starter
+ 1.1.10
+
+
+ p6spy
+ p6spy
+ 3.8.0
+
+
+
\ No newline at end of file
diff --git a/samples/dynamic-druid-mybatis-sample/src/main/java/com/baomidou/samples/druid/mybatis/Application.java b/samples/dynamic-druid-mybatis-sample/src/main/java/com/baomidou/samples/druid/mybatis/Application.java
new file mode 100644
index 0000000..a5803f9
--- /dev/null
+++ b/samples/dynamic-druid-mybatis-sample/src/main/java/com/baomidou/samples/druid/mybatis/Application.java
@@ -0,0 +1,16 @@
+package com.baomidou.samples.druid.mybatis;
+
+import com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceAutoConfigure;
+import org.mybatis.spring.annotation.MapperScan;
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+
+@SpringBootApplication(exclude = DruidDataSourceAutoConfigure.class)
+@MapperScan("com.baomidou.samples.druid.mybatis.mapper")
+public class Application {
+
+ public static void main(String[] args) {
+ SpringApplication.run(Application.class, args);
+ }
+
+}
\ No newline at end of file
diff --git a/samples/dynamic-druid-mybatis-sample/src/main/java/com/baomidou/samples/druid/mybatis/entity/User.java b/samples/dynamic-druid-mybatis-sample/src/main/java/com/baomidou/samples/druid/mybatis/entity/User.java
new file mode 100644
index 0000000..76ad779
--- /dev/null
+++ b/samples/dynamic-druid-mybatis-sample/src/main/java/com/baomidou/samples/druid/mybatis/entity/User.java
@@ -0,0 +1,34 @@
+package com.baomidou.samples.druid.mybatis.entity;
+
+public class User {
+
+ private Integer id;
+
+ private String name;
+
+ private Integer age;
+
+ public Integer getId() {
+ return id;
+ }
+
+ public void setId(Integer id) {
+ this.id = id;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public Integer getAge() {
+ return age;
+ }
+
+ public void setAge(Integer age) {
+ this.age = age;
+ }
+}
diff --git a/samples/dynamic-druid-mybatis-sample/src/main/java/com/baomidou/samples/druid/mybatis/mapper/UserMapper.java b/samples/dynamic-druid-mybatis-sample/src/main/java/com/baomidou/samples/druid/mybatis/mapper/UserMapper.java
new file mode 100644
index 0000000..e0ae233
--- /dev/null
+++ b/samples/dynamic-druid-mybatis-sample/src/main/java/com/baomidou/samples/druid/mybatis/mapper/UserMapper.java
@@ -0,0 +1,17 @@
+package com.baomidou.samples.druid.mybatis.mapper;
+
+import com.baomidou.samples.druid.mybatis.entity.User;
+import org.apache.ibatis.annotations.Insert;
+import org.apache.ibatis.annotations.Param;
+import org.apache.ibatis.annotations.Select;
+
+import java.util.List;
+
+public interface UserMapper {
+
+ @Insert("INSERT INTO user (name,age) values (#{name},#{age})")
+ boolean addUser(@Param("name") String name, @Param("age") Integer age);
+
+ @Select("SELECT * FROM user where age > #{age}")
+ List selectUsers(@Param("age") Integer age);
+}
diff --git a/samples/dynamic-druid-mybatis-sample/src/main/java/com/baomidou/samples/druid/mybatis/service/UserService.java b/samples/dynamic-druid-mybatis-sample/src/main/java/com/baomidou/samples/druid/mybatis/service/UserService.java
new file mode 100644
index 0000000..f189b13
--- /dev/null
+++ b/samples/dynamic-druid-mybatis-sample/src/main/java/com/baomidou/samples/druid/mybatis/service/UserService.java
@@ -0,0 +1,15 @@
+package com.baomidou.samples.druid.mybatis.service;
+
+
+import com.baomidou.samples.druid.mybatis.entity.User;
+
+import java.util.List;
+
+public interface UserService {
+
+ void addUser(User user);
+
+ List selectUsersFromDs();
+
+ List selectUserFromDsGroup();
+}
diff --git a/samples/dynamic-druid-mybatis-sample/src/main/java/com/baomidou/samples/druid/mybatis/service/impl/UserServiceImpl.java b/samples/dynamic-druid-mybatis-sample/src/main/java/com/baomidou/samples/druid/mybatis/service/impl/UserServiceImpl.java
new file mode 100644
index 0000000..1773cf1
--- /dev/null
+++ b/samples/dynamic-druid-mybatis-sample/src/main/java/com/baomidou/samples/druid/mybatis/service/impl/UserServiceImpl.java
@@ -0,0 +1,35 @@
+package com.baomidou.samples.druid.mybatis.service.impl;
+
+
+import com.baomidou.dynamic.datasource.annotation.DS;
+import com.baomidou.samples.druid.mybatis.entity.User;
+import com.baomidou.samples.druid.mybatis.mapper.UserMapper;
+import com.baomidou.samples.druid.mybatis.service.UserService;
+import org.springframework.stereotype.Service;
+
+import javax.annotation.Resource;
+import java.util.List;
+
+@Service
+public class UserServiceImpl implements UserService {
+
+ @Resource
+ private UserMapper userMapper;
+
+ @Override
+ public void addUser(User user) {
+ userMapper.addUser(user.getName(), user.getAge());
+ }
+
+ @DS("slave_1")
+ @Override
+ public List selectUsersFromDs() {
+ return userMapper.selectUsers(1);
+ }
+
+ @DS("slave")
+ @Override
+ public List selectUserFromDsGroup() {
+ return userMapper.selectUsers(1);
+ }
+}
diff --git a/samples/dynamic-druid-mybatis-sample/src/main/resources/application.yml b/samples/dynamic-druid-mybatis-sample/src/main/resources/application.yml
new file mode 100644
index 0000000..2520e8d
--- /dev/null
+++ b/samples/dynamic-druid-mybatis-sample/src/main/resources/application.yml
@@ -0,0 +1,69 @@
+spring:
+ datasource:
+ dynamic:
+ p6spy: true
+ # druid: #以下是全局默认值,可以全局更改
+ # initial-size:
+ # max-active:
+ # min-idle:
+ # max-wait:
+ # time-between-eviction-runs-millis:
+ # time-between-log-stats-millis:
+ # stat-sqlmax-size:
+ # min-evictable-idle-time-millis:
+ # max-evictable-idle-time-millis:
+ # test-while-idle:
+ # test-on-borrow:
+ # test-on-return:
+ # validation-query:
+ # validation-query-timeout:
+ # use-global-datasource-stat:
+ # async-init:
+ # clear-filters-enable:
+ # reset-stat-enable:
+ # not-full-timeout-retry-count:
+ # max-wait-thread-count:
+ # fail-fast:
+ # phyTimeout-millis:
+ # keep-alive:
+ # pool-prepared-statements:
+ # init-variants:
+ # init-global-variants:
+ # use-unfair-lock:
+ # kill-when-socket-read-timeout:
+ # connection-properties:
+ # max-pool-prepared-statement-per-connection-size:
+ # init-connection-sqls:
+ # share-prepared-statements:
+ # connection-errorretry-attempts:
+ # break-after-acquire-failure:
+ # filters: stat,wall # 注意这个值和druid原生不一致,默认启动了stat,wall
+ datasource:
+ master:
+ username: sa
+ password: "LYIXYTfaq9ug7bqAfcoU1gQovp/Atx7wsdJ5D7oFN5QMqZUI4OGHyMkCA7IxtYAIQr/8cMVFGo9oa/mqtMrzmQ=="
+ url: jdbc:h2:mem:test
+ driver-class-name: org.h2.Driver
+ druid: #这里可以重写默认值
+ initial-size: 5
+ public-key: MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAKUVA/IL/iON8f63bv2i/pIAK+1sXY228slLkTKrI9axwBMIoPV7+PqdRTv6uqMl3j6nei0EDBWEu/Wp/qOQ/ScCAwEAAQ==
+ slave_1:
+ username: sa
+ password: "123456"
+ url: jdbc:h2:mem:test
+ driver-class-name: org.h2.Driver
+ druid:
+ initial-size: 6
+ slave_2:
+ username: sa
+ password: "123456"
+ url: jdbc:h2:mem:test
+ driver-class-name: org.h2.Driver
+ slave_3:
+ username: sa
+ password: "123456"
+ url: jdbc:h2:mem:test
+ driver-class-name: org.h2.Driver
+logging:
+ level:
+ com.baomidou: debug
\ No newline at end of file
diff --git a/samples/dynamic-druid-mybatis-sample/src/main/resources/spy.properties b/samples/dynamic-druid-mybatis-sample/src/main/resources/spy.properties
new file mode 100644
index 0000000..3358547
--- /dev/null
+++ b/samples/dynamic-druid-mybatis-sample/src/main/resources/spy.properties
@@ -0,0 +1 @@
+appender=com.p6spy.engine.spy.appender.Slf4JLogger
\ No newline at end of file
diff --git a/samples/dynamic-druid-mybatis-sample/src/test/java/com/baomidou/samples/druid/mybatis/test/ApplicationTest.java b/samples/dynamic-druid-mybatis-sample/src/test/java/com/baomidou/samples/druid/mybatis/test/ApplicationTest.java
new file mode 100644
index 0000000..0f2788e
--- /dev/null
+++ b/samples/dynamic-druid-mybatis-sample/src/test/java/com/baomidou/samples/druid/mybatis/test/ApplicationTest.java
@@ -0,0 +1,65 @@
+package com.baomidou.samples.druid.mybatis.test;
+
+import com.baomidou.samples.druid.mybatis.Application;
+import com.baomidou.samples.druid.mybatis.entity.User;
+import com.baomidou.samples.druid.mybatis.service.UserService;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.test.context.junit4.SpringRunner;
+
+import javax.sql.DataSource;
+import java.sql.Connection;
+import java.sql.SQLException;
+import java.util.Random;
+
+@RunWith(SpringRunner.class)
+@SpringBootTest(classes = Application.class)
+public class ApplicationTest {
+
+ private Random random = new Random();
+
+ @Autowired
+ private UserService userService;
+
+ @Autowired
+ private DataSource dataSource;
+
+ @Before
+ public void beforeTest() {
+ try {
+ Connection connection = dataSource.getConnection();
+ connection.createStatement().execute("CREATE TABLE IF NOT EXISTS USER (\n" +
+ " id BIGINT(20) NOT NULL AUTO_INCREMENT,\n" +
+ " name VARCHAR(30) NULL DEFAULT NULL ,\n" +
+ " age INT(11) NULL DEFAULT NULL ,\n" +
+ " PRIMARY KEY (id)\n" +
+ ");");
+ connection.close();
+ } catch (SQLException e) {
+ e.printStackTrace();
+ }
+ }
+
+
+ @Test
+ public void addUser() {
+ User user = new User();
+ user.setName("测试用户" + random.nextInt());
+ user.setAge(random.nextInt(100));
+ userService.addUser(user);
+ }
+
+ @Test
+ public void selectUsersFromDs() {
+ userService.selectUsersFromDs();
+ }
+
+ @Test
+ public void selectUserFromDsGroup() {
+ userService.selectUserFromDsGroup();
+ }
+
+}
\ No newline at end of file
diff --git a/samples/dynamic-jdbc-template-sample/pom.xml b/samples/dynamic-jdbc-template-sample/pom.xml
new file mode 100644
index 0000000..6feb7ba
--- /dev/null
+++ b/samples/dynamic-jdbc-template-sample/pom.xml
@@ -0,0 +1,20 @@
+
+
+
+ dynamic-datsource-samples
+ com.baomidou
+ 1.0.0
+
+ 4.0.0
+
+ dynamic-jdbc-template-sample
+
+
+
+ org.springframework.boot
+ spring-boot-starter-jdbc
+
+
+
\ No newline at end of file
diff --git a/samples/dynamic-jdbc-template-sample/src/main/java/com/baomidou/samples/jdbc/Application.java b/samples/dynamic-jdbc-template-sample/src/main/java/com/baomidou/samples/jdbc/Application.java
new file mode 100644
index 0000000..7cc3883
--- /dev/null
+++ b/samples/dynamic-jdbc-template-sample/src/main/java/com/baomidou/samples/jdbc/Application.java
@@ -0,0 +1,22 @@
+package com.baomidou.samples.jdbc;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.context.annotation.Bean;
+import org.springframework.jdbc.core.JdbcTemplate;
+
+import javax.sql.DataSource;
+
+@SpringBootApplication
+public class Application {
+
+ public static void main(String[] args) {
+ SpringApplication.run(Application.class, args);
+ }
+
+ @Bean
+ public JdbcTemplate jdbcTemplate(DataSource dataSource) {
+ return new JdbcTemplate(dataSource);
+ }
+
+}
\ No newline at end of file
diff --git a/samples/dynamic-jdbc-template-sample/src/main/java/com/baomidou/samples/jdbc/entity/User.java b/samples/dynamic-jdbc-template-sample/src/main/java/com/baomidou/samples/jdbc/entity/User.java
new file mode 100644
index 0000000..bf2ac67
--- /dev/null
+++ b/samples/dynamic-jdbc-template-sample/src/main/java/com/baomidou/samples/jdbc/entity/User.java
@@ -0,0 +1,34 @@
+package com.baomidou.samples.jdbc.entity;
+
+public class User {
+
+ private Integer id;
+
+ private String name;
+
+ private Integer age;
+
+ public Integer getId() {
+ return id;
+ }
+
+ public void setId(Integer id) {
+ this.id = id;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public Integer getAge() {
+ return age;
+ }
+
+ public void setAge(Integer age) {
+ this.age = age;
+ }
+}
diff --git a/samples/dynamic-jdbc-template-sample/src/main/java/com/baomidou/samples/jdbc/service/UserService.java b/samples/dynamic-jdbc-template-sample/src/main/java/com/baomidou/samples/jdbc/service/UserService.java
new file mode 100644
index 0000000..b9730ae
--- /dev/null
+++ b/samples/dynamic-jdbc-template-sample/src/main/java/com/baomidou/samples/jdbc/service/UserService.java
@@ -0,0 +1,14 @@
+package com.baomidou.samples.jdbc.service;
+
+import com.baomidou.samples.jdbc.entity.User;
+
+import java.util.List;
+
+public interface UserService {
+
+ void addUser(User user);
+
+ List selectUsersFromDs();
+
+ List selectUserFromDsGroup();
+}
diff --git a/samples/dynamic-jdbc-template-sample/src/main/java/com/baomidou/samples/jdbc/service/impl/UserServiceImpl.java b/samples/dynamic-jdbc-template-sample/src/main/java/com/baomidou/samples/jdbc/service/impl/UserServiceImpl.java
new file mode 100644
index 0000000..08cedd7
--- /dev/null
+++ b/samples/dynamic-jdbc-template-sample/src/main/java/com/baomidou/samples/jdbc/service/impl/UserServiceImpl.java
@@ -0,0 +1,35 @@
+package com.baomidou.samples.jdbc.service.impl;
+
+
+import com.baomidou.dynamic.datasource.annotation.DS;
+import com.baomidou.samples.jdbc.entity.User;
+import com.baomidou.samples.jdbc.service.UserService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.jdbc.core.JdbcTemplate;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+
+@Service
+public class UserServiceImpl implements UserService {
+
+ @Autowired
+ private JdbcTemplate jdbcTemplate;
+
+ @Override
+ public void addUser(User user) {
+ jdbcTemplate.update("INSERT INTO user (name,age) VALUES(?, ?)", new Object[]{user.getName(), user.getAge()});
+ }
+
+ @DS("slave_1")
+ @Override
+ public List selectUsersFromDs() {
+ return jdbcTemplate.queryForList("SELECT * FROM user");
+ }
+
+ @DS("slave")
+ @Override
+ public List selectUserFromDsGroup() {
+ return jdbcTemplate.queryForList("SELECT * FROM user");
+ }
+}
diff --git a/samples/dynamic-jdbc-template-sample/src/main/resources/application.yml b/samples/dynamic-jdbc-template-sample/src/main/resources/application.yml
new file mode 100644
index 0000000..60398eb
--- /dev/null
+++ b/samples/dynamic-jdbc-template-sample/src/main/resources/application.yml
@@ -0,0 +1,27 @@
+spring:
+ datasource:
+ dynamic:
+ datasource:
+ master:
+ username: sa
+ password: ""
+ url: jdbc:h2:mem:test
+ driver-class-name: org.h2.Driver
+ slave_1:
+ username: sa
+ password: ""
+ url: jdbc:h2:mem:test
+ driver-class-name: org.h2.Driver
+ slave_2:
+ username: sa
+ password: ""
+ url: jdbc:h2:mem:test
+ driver-class-name: org.h2.Driver
+ slave_3:
+ username: sa
+ password: ""
+ url: jdbc:h2:mem:test
+ driver-class-name: org.h2.Driver
+logging:
+ level:
+ com.baomidou: debug
\ No newline at end of file
diff --git a/samples/dynamic-jdbc-template-sample/src/test/java/com/baomidou/samples/jdbc/test/ApplicationTest.java b/samples/dynamic-jdbc-template-sample/src/test/java/com/baomidou/samples/jdbc/test/ApplicationTest.java
new file mode 100644
index 0000000..c6ec9d6
--- /dev/null
+++ b/samples/dynamic-jdbc-template-sample/src/test/java/com/baomidou/samples/jdbc/test/ApplicationTest.java
@@ -0,0 +1,64 @@
+package com.baomidou.samples.jdbc.test;
+
+import com.baomidou.samples.jdbc.Application;
+import com.baomidou.samples.jdbc.entity.User;
+import com.baomidou.samples.jdbc.service.UserService;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.test.context.junit4.SpringRunner;
+
+import javax.sql.DataSource;
+import java.sql.Connection;
+import java.sql.SQLException;
+import java.util.Random;
+
+@RunWith(SpringRunner.class)
+@SpringBootTest(classes = Application.class)
+public class ApplicationTest {
+
+ private Random random = new Random();
+
+ @Autowired
+ private UserService userService;
+
+ @Autowired
+ private DataSource dataSource;
+
+ @Before
+ public void beforeTest() {
+ try {
+ Connection connection = dataSource.getConnection();
+ connection.createStatement().execute("CREATE TABLE IF NOT EXISTS USER (\n" +
+ " id BIGINT(20) NOT NULL AUTO_INCREMENT,\n" +
+ " name VARCHAR(30) NULL DEFAULT NULL ,\n" +
+ " age INT(11) NULL DEFAULT NULL ,\n" +
+ " PRIMARY KEY (id)\n" +
+ ");");
+ connection.close();
+ } catch (SQLException e) {
+ e.printStackTrace();
+ }
+ }
+
+
+ @Test
+ public void addUser() {
+ User user = new User();
+ user.setName("测试用户" + random.nextInt());
+ user.setAge(random.nextInt(100));
+ userService.addUser(user);
+ }
+
+ @Test
+ public void selectUsersFromDs() {
+ userService.selectUsersFromDs();
+ }
+
+ @Test
+ public void selectUserFromDsGroup() {
+ userService.selectUserFromDsGroup();
+ }
+}
diff --git a/samples/dynamic-mybatis-sample/pom.xml b/samples/dynamic-mybatis-sample/pom.xml
new file mode 100644
index 0000000..58d1252
--- /dev/null
+++ b/samples/dynamic-mybatis-sample/pom.xml
@@ -0,0 +1,22 @@
+
+
+
+ dynamic-datsource-samples
+ com.baomidou
+ 1.0.0
+
+ 4.0.0
+
+ dynamic-mybatis-sample
+
+
+
+ org.mybatis.spring.boot
+ mybatis-spring-boot-starter
+ 1.3.2
+
+
+
+
\ No newline at end of file
diff --git a/samples/dynamic-mybatis-sample/src/main/java/com/baomidou/samples/mybatis/Application.java b/samples/dynamic-mybatis-sample/src/main/java/com/baomidou/samples/mybatis/Application.java
new file mode 100644
index 0000000..77931a1
--- /dev/null
+++ b/samples/dynamic-mybatis-sample/src/main/java/com/baomidou/samples/mybatis/Application.java
@@ -0,0 +1,15 @@
+package com.baomidou.samples.mybatis;
+
+import org.mybatis.spring.annotation.MapperScan;
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+
+@SpringBootApplication
+@MapperScan("com.baomidou.samples.mybatis.mapper")
+public class Application {
+
+ public static void main(String[] args) {
+ SpringApplication.run(Application.class, args);
+ }
+
+}
\ No newline at end of file
diff --git a/samples/dynamic-mybatis-sample/src/main/java/com/baomidou/samples/mybatis/entity/User.java b/samples/dynamic-mybatis-sample/src/main/java/com/baomidou/samples/mybatis/entity/User.java
new file mode 100644
index 0000000..a0cd06e
--- /dev/null
+++ b/samples/dynamic-mybatis-sample/src/main/java/com/baomidou/samples/mybatis/entity/User.java
@@ -0,0 +1,34 @@
+package com.baomidou.samples.mybatis.entity;
+
+public class User {
+
+ private Integer id;
+
+ private String name;
+
+ private Integer age;
+
+ public Integer getId() {
+ return id;
+ }
+
+ public void setId(Integer id) {
+ this.id = id;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public Integer getAge() {
+ return age;
+ }
+
+ public void setAge(Integer age) {
+ this.age = age;
+ }
+}
diff --git a/samples/dynamic-mybatis-sample/src/main/java/com/baomidou/samples/mybatis/mapper/UserMapper.java b/samples/dynamic-mybatis-sample/src/main/java/com/baomidou/samples/mybatis/mapper/UserMapper.java
new file mode 100644
index 0000000..8940fa4
--- /dev/null
+++ b/samples/dynamic-mybatis-sample/src/main/java/com/baomidou/samples/mybatis/mapper/UserMapper.java
@@ -0,0 +1,18 @@
+package com.baomidou.samples.mybatis.mapper;
+
+import com.baomidou.samples.mybatis.entity.User;
+import org.apache.ibatis.annotations.Insert;
+import org.apache.ibatis.annotations.Param;
+import org.apache.ibatis.annotations.Select;
+
+import java.util.List;
+
+//@DS("slave")这里可以使用但不建议,不要和service同时使用
+public interface UserMapper {
+
+ @Insert("INSERT INTO user (name,age) values (#{name},#{age})")
+ boolean addUser(@Param("name") String name, @Param("age") Integer age);
+
+ @Select("SELECT * FROM user")
+ List selectUsers();
+}
diff --git a/samples/dynamic-mybatis-sample/src/main/java/com/baomidou/samples/mybatis/service/UserService.java b/samples/dynamic-mybatis-sample/src/main/java/com/baomidou/samples/mybatis/service/UserService.java
new file mode 100644
index 0000000..b2fdc3d
--- /dev/null
+++ b/samples/dynamic-mybatis-sample/src/main/java/com/baomidou/samples/mybatis/service/UserService.java
@@ -0,0 +1,15 @@
+package com.baomidou.samples.mybatis.service;
+
+
+import com.baomidou.samples.mybatis.entity.User;
+
+import java.util.List;
+
+public interface UserService {
+
+ void addUser(User user);
+
+ List selectUsersFromDs();
+
+ List selectUserFromDsGroup();
+}
diff --git a/samples/dynamic-mybatis-sample/src/main/java/com/baomidou/samples/mybatis/service/impl/UserServiceImpl.java b/samples/dynamic-mybatis-sample/src/main/java/com/baomidou/samples/mybatis/service/impl/UserServiceImpl.java
new file mode 100644
index 0000000..3b1cf08
--- /dev/null
+++ b/samples/dynamic-mybatis-sample/src/main/java/com/baomidou/samples/mybatis/service/impl/UserServiceImpl.java
@@ -0,0 +1,35 @@
+package com.baomidou.samples.mybatis.service.impl;
+
+
+import com.baomidou.dynamic.datasource.annotation.DS;
+import com.baomidou.samples.mybatis.entity.User;
+import com.baomidou.samples.mybatis.mapper.UserMapper;
+import com.baomidou.samples.mybatis.service.UserService;
+import org.springframework.stereotype.Service;
+
+import javax.annotation.Resource;
+import java.util.List;
+
+@Service
+public class UserServiceImpl implements UserService {
+
+ @Resource
+ private UserMapper userMapper;
+
+ @Override
+ public void addUser(User user) {
+ userMapper.addUser(user.getName(), user.getAge());
+ }
+
+ @DS("slave_1")
+ @Override
+ public List selectUsersFromDs() {
+ return userMapper.selectUsers();
+ }
+
+ @DS("slave")
+ @Override
+ public List selectUserFromDsGroup() {
+ return userMapper.selectUsers();
+ }
+}
diff --git a/samples/dynamic-mybatis-sample/src/main/resources/application.yml b/samples/dynamic-mybatis-sample/src/main/resources/application.yml
new file mode 100644
index 0000000..60398eb
--- /dev/null
+++ b/samples/dynamic-mybatis-sample/src/main/resources/application.yml
@@ -0,0 +1,27 @@
+spring:
+ datasource:
+ dynamic:
+ datasource:
+ master:
+ username: sa
+ password: ""
+ url: jdbc:h2:mem:test
+ driver-class-name: org.h2.Driver
+ slave_1:
+ username: sa
+ password: ""
+ url: jdbc:h2:mem:test
+ driver-class-name: org.h2.Driver
+ slave_2:
+ username: sa
+ password: ""
+ url: jdbc:h2:mem:test
+ driver-class-name: org.h2.Driver
+ slave_3:
+ username: sa
+ password: ""
+ url: jdbc:h2:mem:test
+ driver-class-name: org.h2.Driver
+logging:
+ level:
+ com.baomidou: debug
\ No newline at end of file
diff --git a/samples/dynamic-mybatis-sample/src/test/java/com/baomidou/samples/mybatis/test/ApplicationTest.java b/samples/dynamic-mybatis-sample/src/test/java/com/baomidou/samples/mybatis/test/ApplicationTest.java
new file mode 100644
index 0000000..82a563b
--- /dev/null
+++ b/samples/dynamic-mybatis-sample/src/test/java/com/baomidou/samples/mybatis/test/ApplicationTest.java
@@ -0,0 +1,65 @@
+package com.baomidou.samples.mybatis.test;
+
+
+import com.baomidou.samples.mybatis.Application;
+import com.baomidou.samples.mybatis.entity.User;
+import com.baomidou.samples.mybatis.service.UserService;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.test.context.junit4.SpringRunner;
+
+import javax.sql.DataSource;
+import java.sql.Connection;
+import java.sql.SQLException;
+import java.util.Random;
+
+@RunWith(SpringRunner.class)
+@SpringBootTest(classes = Application.class)
+public class ApplicationTest {
+
+ private Random random = new Random();
+
+ @Autowired
+ private UserService userService;
+
+ @Autowired
+ private DataSource dataSource;
+
+ @Before
+ public void beforeTest() {
+ try {
+ Connection connection = dataSource.getConnection();
+ connection.createStatement().execute("CREATE TABLE IF NOT EXISTS USER (\n" +
+ " id BIGINT(20) NOT NULL AUTO_INCREMENT,\n" +
+ " name VARCHAR(30) NULL DEFAULT NULL ,\n" +
+ " age INT(11) NULL DEFAULT NULL ,\n" +
+ " PRIMARY KEY (id)\n" +
+ ");");
+ connection.close();
+ } catch (SQLException e) {
+ e.printStackTrace();
+ }
+ }
+
+
+ @Test
+ public void addUser() {
+ User user = new User();
+ user.setName("测试用户" + random.nextInt());
+ user.setAge(random.nextInt(100));
+ userService.addUser(user);
+ }
+
+ @Test
+ public void selectUsersFromDs() {
+ userService.selectUsersFromDs();
+ }
+
+ @Test
+ public void selectUserFromDsGroup() {
+ userService.selectUserFromDsGroup();
+ }
+}
diff --git a/samples/dynamic-mybatis-sample/transaction-logs/tmlog49.log b/samples/dynamic-mybatis-sample/transaction-logs/tmlog49.log
new file mode 100644
index 0000000..e69de29
diff --git a/samples/dynamic-mybatisplus2-sample/pom.xml b/samples/dynamic-mybatisplus2-sample/pom.xml
new file mode 100644
index 0000000..30638c1
--- /dev/null
+++ b/samples/dynamic-mybatisplus2-sample/pom.xml
@@ -0,0 +1,22 @@
+
+
+
+ dynamic-datsource-samples
+ com.baomidou
+ 1.0.0
+
+ 4.0.0
+
+ dynamic-mybatisplus2-sample
+
+
+
+ com.baomidou
+ mybatis-plus-boot-starter
+ 2.3.1
+
+
+
+
\ No newline at end of file
diff --git a/samples/dynamic-mybatisplus2-sample/src/main/java/com/baomidou/samples/mybatisplus2/Application.java b/samples/dynamic-mybatisplus2-sample/src/main/java/com/baomidou/samples/mybatisplus2/Application.java
new file mode 100644
index 0000000..f83177c
--- /dev/null
+++ b/samples/dynamic-mybatisplus2-sample/src/main/java/com/baomidou/samples/mybatisplus2/Application.java
@@ -0,0 +1,15 @@
+package com.baomidou.samples.mybatisplus2;
+
+import org.mybatis.spring.annotation.MapperScan;
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+
+@SpringBootApplication
+@MapperScan("com.baomidou.samples.mybatisplus2.mapper")
+public class Application {
+
+ public static void main(String[] args) {
+ SpringApplication.run(Application.class, args);
+ }
+
+}
\ No newline at end of file
diff --git a/samples/dynamic-mybatisplus2-sample/src/main/java/com/baomidou/samples/mybatisplus2/entity/User.java b/samples/dynamic-mybatisplus2-sample/src/main/java/com/baomidou/samples/mybatisplus2/entity/User.java
new file mode 100644
index 0000000..fea7ad5
--- /dev/null
+++ b/samples/dynamic-mybatisplus2-sample/src/main/java/com/baomidou/samples/mybatisplus2/entity/User.java
@@ -0,0 +1,38 @@
+package com.baomidou.samples.mybatisplus2.entity;
+
+import com.baomidou.mybatisplus.annotations.TableId;
+import com.baomidou.mybatisplus.enums.IdType;
+
+public class User {
+
+ @TableId(type = IdType.AUTO)
+ private Integer id;
+
+ private String name;
+
+ private Integer age;
+
+ public Integer getId() {
+ return id;
+ }
+
+ public void setId(Integer id) {
+ this.id = id;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public Integer getAge() {
+ return age;
+ }
+
+ public void setAge(Integer age) {
+ this.age = age;
+ }
+}
diff --git a/samples/dynamic-mybatisplus2-sample/src/main/java/com/baomidou/samples/mybatisplus2/mapper/UserMapper.java b/samples/dynamic-mybatisplus2-sample/src/main/java/com/baomidou/samples/mybatisplus2/mapper/UserMapper.java
new file mode 100644
index 0000000..142d075
--- /dev/null
+++ b/samples/dynamic-mybatisplus2-sample/src/main/java/com/baomidou/samples/mybatisplus2/mapper/UserMapper.java
@@ -0,0 +1,7 @@
+package com.baomidou.samples.mybatisplus2.mapper;
+
+import com.baomidou.mybatisplus.mapper.BaseMapper;
+import com.baomidou.samples.mybatisplus2.entity.User;
+
+public interface UserMapper extends BaseMapper {
+}
diff --git a/samples/dynamic-mybatisplus2-sample/src/main/java/com/baomidou/samples/mybatisplus2/service/UserService.java b/samples/dynamic-mybatisplus2-sample/src/main/java/com/baomidou/samples/mybatisplus2/service/UserService.java
new file mode 100644
index 0000000..e7b4c16
--- /dev/null
+++ b/samples/dynamic-mybatisplus2-sample/src/main/java/com/baomidou/samples/mybatisplus2/service/UserService.java
@@ -0,0 +1,11 @@
+package com.baomidou.samples.mybatisplus2.service;
+
+
+import com.baomidou.mybatisplus.service.IService;
+import com.baomidou.samples.mybatisplus2.entity.User;
+
+public interface UserService extends IService {
+
+ void addUser(User user);
+
+}
diff --git a/samples/dynamic-mybatisplus2-sample/src/main/java/com/baomidou/samples/mybatisplus2/service/impl/UserServiceImpl.java b/samples/dynamic-mybatisplus2-sample/src/main/java/com/baomidou/samples/mybatisplus2/service/impl/UserServiceImpl.java
new file mode 100644
index 0000000..38c3d9d
--- /dev/null
+++ b/samples/dynamic-mybatisplus2-sample/src/main/java/com/baomidou/samples/mybatisplus2/service/impl/UserServiceImpl.java
@@ -0,0 +1,20 @@
+package com.baomidou.samples.mybatisplus2.service.impl;
+
+
+import com.baomidou.dynamic.datasource.annotation.DS;
+import com.baomidou.mybatisplus.service.impl.ServiceImpl;
+import com.baomidou.samples.mybatisplus2.entity.User;
+import com.baomidou.samples.mybatisplus2.mapper.UserMapper;
+import com.baomidou.samples.mybatisplus2.service.UserService;
+import org.springframework.stereotype.Service;
+
+@Service
+@DS("slave")
+public class UserServiceImpl extends ServiceImpl implements UserService {
+
+ @Override
+ @DS("master")//这里必须包一层,不能调用mp默认的插入,因为会走到从库去
+ public void addUser(User user) {
+ baseMapper.insert(user);
+ }
+}
diff --git a/samples/dynamic-mybatisplus2-sample/src/main/resources/application.yml b/samples/dynamic-mybatisplus2-sample/src/main/resources/application.yml
new file mode 100644
index 0000000..60398eb
--- /dev/null
+++ b/samples/dynamic-mybatisplus2-sample/src/main/resources/application.yml
@@ -0,0 +1,27 @@
+spring:
+ datasource:
+ dynamic:
+ datasource:
+ master:
+ username: sa
+ password: ""
+ url: jdbc:h2:mem:test
+ driver-class-name: org.h2.Driver
+ slave_1:
+ username: sa
+ password: ""
+ url: jdbc:h2:mem:test
+ driver-class-name: org.h2.Driver
+ slave_2:
+ username: sa
+ password: ""
+ url: jdbc:h2:mem:test
+ driver-class-name: org.h2.Driver
+ slave_3:
+ username: sa
+ password: ""
+ url: jdbc:h2:mem:test
+ driver-class-name: org.h2.Driver
+logging:
+ level:
+ com.baomidou: debug
\ No newline at end of file
diff --git a/samples/dynamic-mybatisplus2-sample/src/test/java/com/baomidou/samples/mybatisplus2/test/ApplicationTest.java b/samples/dynamic-mybatisplus2-sample/src/test/java/com/baomidou/samples/mybatisplus2/test/ApplicationTest.java
new file mode 100644
index 0000000..09788de
--- /dev/null
+++ b/samples/dynamic-mybatisplus2-sample/src/test/java/com/baomidou/samples/mybatisplus2/test/ApplicationTest.java
@@ -0,0 +1,58 @@
+package com.baomidou.samples.mybatisplus2.test;
+
+import com.baomidou.samples.mybatisplus2.Application;
+import com.baomidou.samples.mybatisplus2.entity.User;
+import com.baomidou.samples.mybatisplus2.service.UserService;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.test.context.junit4.SpringRunner;
+
+import javax.sql.DataSource;
+import java.sql.Connection;
+import java.sql.SQLException;
+import java.util.Random;
+
+@RunWith(SpringRunner.class)
+@SpringBootTest(classes = Application.class)
+public class ApplicationTest {
+
+ private Random random = new Random();
+
+ @Autowired
+ private DataSource dataSource;
+ @Autowired
+ private UserService userService;
+
+ @Before
+ public void beforeTest() {
+ try {
+ Connection connection = dataSource.getConnection();
+ connection.createStatement().execute("CREATE TABLE IF NOT EXISTS USER (\n" +
+ " id BIGINT(20) NOT NULL AUTO_INCREMENT,\n" +
+ " name VARCHAR(30) NULL DEFAULT NULL ,\n" +
+ " age INT(11) NULL DEFAULT NULL ,\n" +
+ " PRIMARY KEY (id)\n" +
+ ");");
+ connection.close();
+ } catch (SQLException e) {
+ e.printStackTrace();
+ }
+ }
+
+ @Test
+ public void testAddUser() {
+ User user = new User();
+ user.setName("测试用户" + random.nextInt());
+ user.setAge(random.nextInt(100));
+ userService.addUser(user);
+ }
+
+ @Test
+ public void testSelectUser() {
+ userService.selectList(null);
+ }
+
+}
diff --git a/samples/dynamic-mybatisplus3-sample/pom.xml b/samples/dynamic-mybatisplus3-sample/pom.xml
new file mode 100644
index 0000000..6384f29
--- /dev/null
+++ b/samples/dynamic-mybatisplus3-sample/pom.xml
@@ -0,0 +1,22 @@
+
+
+
+ dynamic-datsource-samples
+ com.baomidou
+ 1.0.0
+
+ 4.0.0
+
+ dynamic-mybatisplus3-sample
+
+
+
+ com.baomidou
+ mybatis-plus-boot-starter
+ 3.0.3
+
+
+
+
\ No newline at end of file
diff --git a/samples/dynamic-mybatisplus3-sample/src/main/java/com/baomidou/samples/mybatisplus/Application.java b/samples/dynamic-mybatisplus3-sample/src/main/java/com/baomidou/samples/mybatisplus/Application.java
new file mode 100644
index 0000000..1df5795
--- /dev/null
+++ b/samples/dynamic-mybatisplus3-sample/src/main/java/com/baomidou/samples/mybatisplus/Application.java
@@ -0,0 +1,15 @@
+package com.baomidou.samples.mybatisplus;
+
+import org.mybatis.spring.annotation.MapperScan;
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+
+@SpringBootApplication
+@MapperScan("com.baomidou.samples.mybatisplus.mapper")
+public class Application {
+
+ public static void main(String[] args) {
+ SpringApplication.run(Application.class, args);
+ }
+
+}
\ No newline at end of file
diff --git a/samples/dynamic-mybatisplus3-sample/src/main/java/com/baomidou/samples/mybatisplus/entity/User.java b/samples/dynamic-mybatisplus3-sample/src/main/java/com/baomidou/samples/mybatisplus/entity/User.java
new file mode 100644
index 0000000..eefc4a1
--- /dev/null
+++ b/samples/dynamic-mybatisplus3-sample/src/main/java/com/baomidou/samples/mybatisplus/entity/User.java
@@ -0,0 +1,38 @@
+package com.baomidou.samples.mybatisplus.entity;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+
+public class User {
+
+ @TableId(type = IdType.AUTO)
+ private Integer id;
+
+ private String name;
+
+ private Integer age;
+
+ public Integer getId() {
+ return id;
+ }
+
+ public void setId(Integer id) {
+ this.id = id;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public Integer getAge() {
+ return age;
+ }
+
+ public void setAge(Integer age) {
+ this.age = age;
+ }
+}
diff --git a/samples/dynamic-mybatisplus3-sample/src/main/java/com/baomidou/samples/mybatisplus/mapper/UserMapper.java b/samples/dynamic-mybatisplus3-sample/src/main/java/com/baomidou/samples/mybatisplus/mapper/UserMapper.java
new file mode 100644
index 0000000..faf2496
--- /dev/null
+++ b/samples/dynamic-mybatisplus3-sample/src/main/java/com/baomidou/samples/mybatisplus/mapper/UserMapper.java
@@ -0,0 +1,7 @@
+package com.baomidou.samples.mybatisplus.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.baomidou.samples.mybatisplus.entity.User;
+
+public interface UserMapper extends BaseMapper {
+}
diff --git a/samples/dynamic-mybatisplus3-sample/src/main/java/com/baomidou/samples/mybatisplus/service/UserService.java b/samples/dynamic-mybatisplus3-sample/src/main/java/com/baomidou/samples/mybatisplus/service/UserService.java
new file mode 100644
index 0000000..5f3b9f2
--- /dev/null
+++ b/samples/dynamic-mybatisplus3-sample/src/main/java/com/baomidou/samples/mybatisplus/service/UserService.java
@@ -0,0 +1,11 @@
+package com.baomidou.samples.mybatisplus.service;
+
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.baomidou.samples.mybatisplus.entity.User;
+
+public interface UserService extends IService {
+
+ void addUser(User user);
+
+}
diff --git a/samples/dynamic-mybatisplus3-sample/src/main/java/com/baomidou/samples/mybatisplus/service/impl/UserServiceImpl.java b/samples/dynamic-mybatisplus3-sample/src/main/java/com/baomidou/samples/mybatisplus/service/impl/UserServiceImpl.java
new file mode 100644
index 0000000..0d53ae1
--- /dev/null
+++ b/samples/dynamic-mybatisplus3-sample/src/main/java/com/baomidou/samples/mybatisplus/service/impl/UserServiceImpl.java
@@ -0,0 +1,20 @@
+package com.baomidou.samples.mybatisplus.service.impl;
+
+
+import com.baomidou.dynamic.datasource.annotation.DS;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.baomidou.samples.mybatisplus.entity.User;
+import com.baomidou.samples.mybatisplus.mapper.UserMapper;
+import com.baomidou.samples.mybatisplus.service.UserService;
+import org.springframework.stereotype.Service;
+
+@Service
+@DS("slave")
+public class UserServiceImpl extends ServiceImpl implements UserService {
+
+ @Override
+ @DS("master")//这里必须包一层,不能调用mp默认的插入,因为会走到从库去
+ public void addUser(User user) {
+ baseMapper.insert(user);
+ }
+}
diff --git a/samples/dynamic-mybatisplus3-sample/src/main/resources/application.yml b/samples/dynamic-mybatisplus3-sample/src/main/resources/application.yml
new file mode 100644
index 0000000..60398eb
--- /dev/null
+++ b/samples/dynamic-mybatisplus3-sample/src/main/resources/application.yml
@@ -0,0 +1,27 @@
+spring:
+ datasource:
+ dynamic:
+ datasource:
+ master:
+ username: sa
+ password: ""
+ url: jdbc:h2:mem:test
+ driver-class-name: org.h2.Driver
+ slave_1:
+ username: sa
+ password: ""
+ url: jdbc:h2:mem:test
+ driver-class-name: org.h2.Driver
+ slave_2:
+ username: sa
+ password: ""
+ url: jdbc:h2:mem:test
+ driver-class-name: org.h2.Driver
+ slave_3:
+ username: sa
+ password: ""
+ url: jdbc:h2:mem:test
+ driver-class-name: org.h2.Driver
+logging:
+ level:
+ com.baomidou: debug
\ No newline at end of file
diff --git a/samples/dynamic-mybatisplus3-sample/src/test/java/com/baomidou/samples/mybatisplus3/test/ApplicationTest.java b/samples/dynamic-mybatisplus3-sample/src/test/java/com/baomidou/samples/mybatisplus3/test/ApplicationTest.java
new file mode 100644
index 0000000..fa91923
--- /dev/null
+++ b/samples/dynamic-mybatisplus3-sample/src/test/java/com/baomidou/samples/mybatisplus3/test/ApplicationTest.java
@@ -0,0 +1,57 @@
+package com.baomidou.samples.mybatisplus3.test;
+
+import com.baomidou.samples.mybatisplus.Application;
+import com.baomidou.samples.mybatisplus.entity.User;
+import com.baomidou.samples.mybatisplus.service.UserService;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.test.context.junit4.SpringRunner;
+
+import javax.sql.DataSource;
+import java.sql.Connection;
+import java.sql.SQLException;
+import java.util.Random;
+
+@RunWith(SpringRunner.class)
+@SpringBootTest(classes = Application.class)
+public class ApplicationTest {
+
+ private Random random = new Random();
+
+ @Autowired
+ private DataSource dataSource;
+ @Autowired
+ private UserService userService;
+
+ @Before
+ public void beforeTest() {
+ try {
+ Connection connection = dataSource.getConnection();
+ connection.createStatement().execute("CREATE TABLE IF NOT EXISTS USER (\n" +
+ " id BIGINT(20) NOT NULL AUTO_INCREMENT,\n" +
+ " name VARCHAR(30) NULL DEFAULT NULL ,\n" +
+ " age INT(11) NULL DEFAULT NULL ,\n" +
+ " PRIMARY KEY (id)\n" +
+ ");");
+ connection.close();
+ } catch (SQLException e) {
+ e.printStackTrace();
+ }
+ }
+
+ @Test
+ public void testAddUser() {
+ User user = new User();
+ user.setName("测试用户" + random.nextInt());
+ user.setAge(random.nextInt(100));
+ userService.addUser(user);
+ }
+
+ @Test
+ public void testSelectUser() {
+ userService.list(null);
+ }
+}
diff --git a/samples/dynamic-nest-sample/pom.xml b/samples/dynamic-nest-sample/pom.xml
new file mode 100644
index 0000000..a925270
--- /dev/null
+++ b/samples/dynamic-nest-sample/pom.xml
@@ -0,0 +1,21 @@
+
+
+
+ dynamic-datsource-samples
+ com.baomidou
+ 1.0.0
+
+ 4.0.0
+
+ dynamic-nest-sample
+
+
+
+ org.mybatis.spring.boot
+ mybatis-spring-boot-starter
+ 1.3.2
+
+
+
\ No newline at end of file
diff --git a/samples/dynamic-nest-sample/src/main/java/com/baomidou/samples/nest/Application.java b/samples/dynamic-nest-sample/src/main/java/com/baomidou/samples/nest/Application.java
new file mode 100644
index 0000000..416c0a5
--- /dev/null
+++ b/samples/dynamic-nest-sample/src/main/java/com/baomidou/samples/nest/Application.java
@@ -0,0 +1,15 @@
+package com.baomidou.samples.nest;
+
+import org.mybatis.spring.annotation.MapperScan;
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+
+@SpringBootApplication
+@MapperScan("com.baomidou.samples.nest.mapper")
+public class Application {
+
+ public static void main(String[] args) {
+ SpringApplication.run(Application.class, args);
+ }
+
+}
\ No newline at end of file
diff --git a/samples/dynamic-nest-sample/src/main/java/com/baomidou/samples/nest/CreateDatabaseOnStarted.java b/samples/dynamic-nest-sample/src/main/java/com/baomidou/samples/nest/CreateDatabaseOnStarted.java
new file mode 100644
index 0000000..39fdc4e
--- /dev/null
+++ b/samples/dynamic-nest-sample/src/main/java/com/baomidou/samples/nest/CreateDatabaseOnStarted.java
@@ -0,0 +1,39 @@
+package com.baomidou.samples.nest;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.context.event.ApplicationStartedEvent;
+import org.springframework.context.ApplicationListener;
+import org.springframework.stereotype.Component;
+
+import javax.sql.DataSource;
+import java.sql.Connection;
+import java.sql.SQLException;
+
+@Component
+public class CreateDatabaseOnStarted implements ApplicationListener {
+
+ @Autowired
+ private DataSource dataSource;
+
+ @Override
+ public void onApplicationEvent(ApplicationStartedEvent event) {
+ try {
+ Connection connection = dataSource.getConnection();
+ connection.createStatement().execute("CREATE TABLE IF NOT EXISTS teacher (\n" +
+ " id BIGINT(20) NOT NULL AUTO_INCREMENT,\n" +
+ " name VARCHAR(30) NULL DEFAULT NULL ,\n" +
+ " age INT(11) NULL DEFAULT NULL ,\n" +
+ " PRIMARY KEY (id)\n" +
+ ");");
+ connection.createStatement().execute("CREATE TABLE IF NOT EXISTS student (\n" +
+ " id BIGINT(20) NOT NULL AUTO_INCREMENT,\n" +
+ " name VARCHAR(30) NULL DEFAULT NULL ,\n" +
+ " age INT(11) NULL DEFAULT NULL ,\n" +
+ " PRIMARY KEY (id)\n" +
+ ");");
+ connection.close();
+ } catch (SQLException e) {
+ e.printStackTrace();
+ }
+ }
+}
diff --git a/samples/dynamic-nest-sample/src/main/java/com/baomidou/samples/nest/controller/TestController.java b/samples/dynamic-nest-sample/src/main/java/com/baomidou/samples/nest/controller/TestController.java
new file mode 100644
index 0000000..8b69a5a
--- /dev/null
+++ b/samples/dynamic-nest-sample/src/main/java/com/baomidou/samples/nest/controller/TestController.java
@@ -0,0 +1,34 @@
+package com.baomidou.samples.nest.controller;
+
+import com.baomidou.samples.nest.service.SchoolService;
+import com.baomidou.samples.nest.service.TeacherService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+@RestController
+public class TestController {
+ @Autowired
+ private TeacherService teacherService;
+
+ @Autowired
+ private SchoolService schoolService;
+
+ @GetMapping("/tx1")
+ public void tx1() {
+ //外层不加事物,里面每个单独加事物(支持,不过感觉没毛用)
+ schoolService.addTeacherAndStudent();
+ }
+
+ @GetMapping("/tx2")
+ public void tx2() {
+ //外层加事物,里面每个也加事物(不支持!!)其实只要加了事物就不支持多库
+ schoolService.addTeacherAndStudentWithTx();
+ }
+
+ @GetMapping("/tx3")
+ public void tx3() {
+ //单独调用加事物单库(支持)
+ teacherService.addTeacherWithTx("tt", 12);
+ }
+}
diff --git a/samples/dynamic-nest-sample/src/main/java/com/baomidou/samples/nest/entiry/Student.java b/samples/dynamic-nest-sample/src/main/java/com/baomidou/samples/nest/entiry/Student.java
new file mode 100644
index 0000000..b788dd8
--- /dev/null
+++ b/samples/dynamic-nest-sample/src/main/java/com/baomidou/samples/nest/entiry/Student.java
@@ -0,0 +1,34 @@
+package com.baomidou.samples.nest.entiry;
+
+public class Student {
+
+ private Integer id;
+
+ private String name;
+
+ private Integer age;
+
+ public Integer getId() {
+ return id;
+ }
+
+ public void setId(Integer id) {
+ this.id = id;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public Integer getAge() {
+ return age;
+ }
+
+ public void setAge(Integer age) {
+ this.age = age;
+ }
+}
diff --git a/samples/dynamic-nest-sample/src/main/java/com/baomidou/samples/nest/entiry/Teacher.java b/samples/dynamic-nest-sample/src/main/java/com/baomidou/samples/nest/entiry/Teacher.java
new file mode 100644
index 0000000..bbd30d5
--- /dev/null
+++ b/samples/dynamic-nest-sample/src/main/java/com/baomidou/samples/nest/entiry/Teacher.java
@@ -0,0 +1,34 @@
+package com.baomidou.samples.nest.entiry;
+
+public class Teacher {
+
+ private Integer id;
+
+ private String name;
+
+ private Integer age;
+
+ public Integer getId() {
+ return id;
+ }
+
+ public void setId(Integer id) {
+ this.id = id;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public Integer getAge() {
+ return age;
+ }
+
+ public void setAge(Integer age) {
+ this.age = age;
+ }
+}
diff --git a/samples/dynamic-nest-sample/src/main/java/com/baomidou/samples/nest/mapper/StudentMapper.java b/samples/dynamic-nest-sample/src/main/java/com/baomidou/samples/nest/mapper/StudentMapper.java
new file mode 100644
index 0000000..c283e57
--- /dev/null
+++ b/samples/dynamic-nest-sample/src/main/java/com/baomidou/samples/nest/mapper/StudentMapper.java
@@ -0,0 +1,17 @@
+package com.baomidou.samples.nest.mapper;
+
+import com.baomidou.samples.nest.entiry.Student;
+import org.apache.ibatis.annotations.Insert;
+import org.apache.ibatis.annotations.Param;
+import org.apache.ibatis.annotations.Select;
+
+import java.util.List;
+
+public interface StudentMapper {
+
+ @Insert("INSERT INTO student (name,age) values (#{name},#{age})")
+ boolean addStudent(@Param("name") String name, @Param("age") Integer age);
+
+ @Select("SELECT * FROM student")
+ List selectStudents();
+}
diff --git a/samples/dynamic-nest-sample/src/main/java/com/baomidou/samples/nest/mapper/TeacherMapper.java b/samples/dynamic-nest-sample/src/main/java/com/baomidou/samples/nest/mapper/TeacherMapper.java
new file mode 100644
index 0000000..395e025
--- /dev/null
+++ b/samples/dynamic-nest-sample/src/main/java/com/baomidou/samples/nest/mapper/TeacherMapper.java
@@ -0,0 +1,17 @@
+package com.baomidou.samples.nest.mapper;
+
+import com.baomidou.samples.nest.entiry.Teacher;
+import org.apache.ibatis.annotations.Insert;
+import org.apache.ibatis.annotations.Param;
+import org.apache.ibatis.annotations.Select;
+
+import java.util.List;
+
+public interface TeacherMapper {
+
+ @Insert("INSERT INTO teacher (name,age) values (#{name},#{age})")
+ boolean addTeacher(@Param("name") String name, @Param("age") Integer age);
+
+ @Select("SELECT * FROM teacher")
+ List selectTeachers();
+}
diff --git a/samples/dynamic-nest-sample/src/main/java/com/baomidou/samples/nest/service/SchoolService.java b/samples/dynamic-nest-sample/src/main/java/com/baomidou/samples/nest/service/SchoolService.java
new file mode 100644
index 0000000..4234b7b
--- /dev/null
+++ b/samples/dynamic-nest-sample/src/main/java/com/baomidou/samples/nest/service/SchoolService.java
@@ -0,0 +1,12 @@
+package com.baomidou.samples.nest.service;
+
+public interface SchoolService {
+
+ void selectTeachersAndStudents();
+
+ void selectTeachersInnerStudents();
+
+ void addTeacherAndStudent();
+
+ void addTeacherAndStudentWithTx();
+}
diff --git a/samples/dynamic-nest-sample/src/main/java/com/baomidou/samples/nest/service/StudentService.java b/samples/dynamic-nest-sample/src/main/java/com/baomidou/samples/nest/service/StudentService.java
new file mode 100644
index 0000000..970f49a
--- /dev/null
+++ b/samples/dynamic-nest-sample/src/main/java/com/baomidou/samples/nest/service/StudentService.java
@@ -0,0 +1,15 @@
+package com.baomidou.samples.nest.service;
+
+import com.baomidou.samples.nest.entiry.Student;
+
+import java.util.List;
+
+public interface StudentService {
+
+ boolean addStudentWithTx(String name, Integer age);
+
+ boolean addStudentNoTx(String name, Integer age);
+
+
+ List selectStudents();
+}
diff --git a/samples/dynamic-nest-sample/src/main/java/com/baomidou/samples/nest/service/TeacherService.java b/samples/dynamic-nest-sample/src/main/java/com/baomidou/samples/nest/service/TeacherService.java
new file mode 100644
index 0000000..9b92991
--- /dev/null
+++ b/samples/dynamic-nest-sample/src/main/java/com/baomidou/samples/nest/service/TeacherService.java
@@ -0,0 +1,18 @@
+package com.baomidou.samples.nest.service;
+
+import com.baomidou.samples.nest.entiry.Teacher;
+
+import java.util.List;
+
+
+public interface TeacherService {
+
+ boolean addTeacherWithTx(String name, Integer age);
+
+ boolean addTeacherNoTx(String name, Integer age);
+
+
+ List selectTeachers();
+
+ void selectTeachersInnerStudents();
+}
diff --git a/samples/dynamic-nest-sample/src/main/java/com/baomidou/samples/nest/service/impl/SchoolServiceImpl.java b/samples/dynamic-nest-sample/src/main/java/com/baomidou/samples/nest/service/impl/SchoolServiceImpl.java
new file mode 100644
index 0000000..1f3b133
--- /dev/null
+++ b/samples/dynamic-nest-sample/src/main/java/com/baomidou/samples/nest/service/impl/SchoolServiceImpl.java
@@ -0,0 +1,42 @@
+package com.baomidou.samples.nest.service.impl;
+
+import com.baomidou.samples.nest.service.SchoolService;
+import com.baomidou.samples.nest.service.StudentService;
+import com.baomidou.samples.nest.service.TeacherService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+@Service
+public class SchoolServiceImpl implements SchoolService {
+
+ @Autowired
+ private TeacherService teacherService;
+
+ @Autowired
+ private StudentService studentService;
+
+ @Override
+ public void selectTeachersAndStudents() {
+ teacherService.selectTeachers();
+ studentService.selectStudents();
+ }
+
+ @Override
+ public void selectTeachersInnerStudents() {
+ teacherService.selectTeachersInnerStudents();
+ }
+
+ @Override
+ public void addTeacherAndStudent() {
+ teacherService.addTeacherWithTx("ss", 1);
+ studentService.addStudentWithTx("tt", 2);
+ }
+
+ @Override
+ @Transactional
+ public void addTeacherAndStudentWithTx() {
+ teacherService.addTeacherWithTx("ss", 1);
+ studentService.addStudentWithTx("tt", 2);
+ }
+}
diff --git a/samples/dynamic-nest-sample/src/main/java/com/baomidou/samples/nest/service/impl/StudentServiceImpl.java b/samples/dynamic-nest-sample/src/main/java/com/baomidou/samples/nest/service/impl/StudentServiceImpl.java
new file mode 100644
index 0000000..63b3882
--- /dev/null
+++ b/samples/dynamic-nest-sample/src/main/java/com/baomidou/samples/nest/service/impl/StudentServiceImpl.java
@@ -0,0 +1,35 @@
+package com.baomidou.samples.nest.service.impl;
+
+import com.baomidou.dynamic.datasource.annotation.DS;
+import com.baomidou.samples.nest.entiry.Student;
+import com.baomidou.samples.nest.mapper.StudentMapper;
+import com.baomidou.samples.nest.service.StudentService;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import javax.annotation.Resource;
+import java.util.List;
+
+@Service
+@DS("student")
+public class StudentServiceImpl implements StudentService {
+
+ @Resource
+ private StudentMapper studentMapper;
+
+ @Override
+ @Transactional
+ public boolean addStudentWithTx(String name, Integer age) {
+ return studentMapper.addStudent(name, age);
+ }
+
+ @Override
+ public boolean addStudentNoTx(String name, Integer age) {
+ return studentMapper.addStudent(name, age);
+ }
+
+ @Override
+ public List selectStudents() {
+ return studentMapper.selectStudents();
+ }
+}
diff --git a/samples/dynamic-nest-sample/src/main/java/com/baomidou/samples/nest/service/impl/TeacherServiceImpl.java b/samples/dynamic-nest-sample/src/main/java/com/baomidou/samples/nest/service/impl/TeacherServiceImpl.java
new file mode 100644
index 0000000..9d7550b
--- /dev/null
+++ b/samples/dynamic-nest-sample/src/main/java/com/baomidou/samples/nest/service/impl/TeacherServiceImpl.java
@@ -0,0 +1,45 @@
+package com.baomidou.samples.nest.service.impl;
+
+import com.baomidou.dynamic.datasource.annotation.DS;
+import com.baomidou.samples.nest.entiry.Teacher;
+import com.baomidou.samples.nest.mapper.TeacherMapper;
+import com.baomidou.samples.nest.service.StudentService;
+import com.baomidou.samples.nest.service.TeacherService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import javax.annotation.Resource;
+import java.util.List;
+
+@Service
+@DS("teacher")
+public class TeacherServiceImpl implements TeacherService {
+
+ @Resource
+ private TeacherMapper teacherMapper;
+ @Autowired
+ private StudentService studentService;
+
+ @Override
+ @Transactional
+ public boolean addTeacherWithTx(String name, Integer age) {
+ return teacherMapper.addTeacher(name, age);
+ }
+
+ @Override
+ public boolean addTeacherNoTx(String name, Integer age) {
+ return teacherMapper.addTeacher(name, age);
+ }
+
+ @Override
+ public List selectTeachers() {
+ return teacherMapper.selectTeachers();
+ }
+
+ @Override
+ public void selectTeachersInnerStudents() {
+ teacherMapper.selectTeachers();
+ studentService.selectStudents();
+ }
+}
diff --git a/samples/dynamic-nest-sample/src/main/resources/application.yml b/samples/dynamic-nest-sample/src/main/resources/application.yml
new file mode 100644
index 0000000..e735650
--- /dev/null
+++ b/samples/dynamic-nest-sample/src/main/resources/application.yml
@@ -0,0 +1,27 @@
+spring:
+ datasource:
+ dynamic:
+ datasource:
+ master:
+ username: sa
+ password: ""
+ url: jdbc:h2:mem:test;DB_CLOSE_ON_EXIT=FALSE
+ driver-class-name: org.h2.Driver
+ salve:
+ username: sa
+ password: ""
+ url: jdbc:h2:mem:test;DB_CLOSE_ON_EXIT=FALSE
+ driver-class-name: org.h2.Driver
+ teacher:
+ username: sa
+ password: ""
+ url: jdbc:h2:mem:test;DB_CLOSE_ON_EXIT=FALSE
+ driver-class-name: org.h2.Driver
+ student:
+ username: sa
+ password: ""
+ url: jdbc:h2:mem:test;DB_CLOSE_ON_EXIT=FALSE
+ driver-class-name: org.h2.Driver
+logging:
+ level:
+ com.baomidou: debug
\ No newline at end of file
diff --git a/samples/dynamic-nest-sample/src/test/java/com/baomidou/samples/nest/test/ApplicationTest.java b/samples/dynamic-nest-sample/src/test/java/com/baomidou/samples/nest/test/ApplicationTest.java
new file mode 100644
index 0000000..91430af
--- /dev/null
+++ b/samples/dynamic-nest-sample/src/test/java/com/baomidou/samples/nest/test/ApplicationTest.java
@@ -0,0 +1,81 @@
+package com.baomidou.samples.nest.test;
+
+
+import com.baomidou.samples.nest.Application;
+import com.baomidou.samples.nest.service.SchoolService;
+import com.baomidou.samples.nest.service.StudentService;
+import com.baomidou.samples.nest.service.TeacherService;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.test.context.junit4.SpringRunner;
+
+import javax.sql.DataSource;
+import java.sql.Connection;
+import java.sql.SQLException;
+import java.util.Random;
+
+@RunWith(SpringRunner.class)
+@SpringBootTest(classes = Application.class)
+
+public class ApplicationTest {
+
+ private Random random = new Random();
+
+ @Autowired
+ private TeacherService teacherService;
+ @Autowired
+ private StudentService studentService;
+ @Autowired
+ private SchoolService schoolService;
+
+ @Autowired
+ private DataSource dataSource;
+
+ @Before
+ public void beforeTest() {
+ try {
+ Connection connection = dataSource.getConnection();
+ connection.createStatement().execute("CREATE TABLE IF NOT EXISTS teacher (\n" +
+ " id BIGINT(20) NOT NULL AUTO_INCREMENT,\n" +
+ " name VARCHAR(30) NULL DEFAULT NULL ,\n" +
+ " age INT(11) NULL DEFAULT NULL ,\n" +
+ " PRIMARY KEY (id)\n" +
+ ");");
+ connection.createStatement().execute("CREATE TABLE IF NOT EXISTS student (\n" +
+ " id BIGINT(20) NOT NULL AUTO_INCREMENT,\n" +
+ " name VARCHAR(30) NULL DEFAULT NULL ,\n" +
+ " age INT(11) NULL DEFAULT NULL ,\n" +
+ " PRIMARY KEY (id)\n" +
+ ");");
+ connection.close();
+ } catch (SQLException e) {
+ e.printStackTrace();
+ }
+ }
+
+
+ @Test
+ public void nest1() {
+ //直接在controller
+ teacherService.selectTeachers();
+ studentService.selectStudents();
+ }
+
+ @Test
+ public void nest2() {
+ schoolService.selectTeachersAndStudents();
+ }
+
+ @Test
+ public void nest3() {
+ schoolService.selectTeachersInnerStudents();
+ }
+
+ @Test
+ public void tx() {
+ teacherService.selectTeachers();
+ }
+}
\ No newline at end of file
diff --git a/samples/dynamic-spel-sample/pom.xml b/samples/dynamic-spel-sample/pom.xml
new file mode 100644
index 0000000..fae8ccc
--- /dev/null
+++ b/samples/dynamic-spel-sample/pom.xml
@@ -0,0 +1,22 @@
+
+
+
+ dynamic-datsource-samples
+ com.baomidou
+ 1.0.0
+
+ 4.0.0
+
+ dynamic-spel-sample
+
+
+
+ org.mybatis.spring.boot
+ mybatis-spring-boot-starter
+ 1.3.2
+
+
+
+
\ No newline at end of file
diff --git a/samples/dynamic-spel-sample/src/main/java/com/baomidou/samples/spel/Application.java b/samples/dynamic-spel-sample/src/main/java/com/baomidou/samples/spel/Application.java
new file mode 100644
index 0000000..2f24ff8
--- /dev/null
+++ b/samples/dynamic-spel-sample/src/main/java/com/baomidou/samples/spel/Application.java
@@ -0,0 +1,15 @@
+package com.baomidou.samples.spel;
+
+import org.mybatis.spring.annotation.MapperScan;
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+
+@SpringBootApplication
+@MapperScan("com.baomidou.samples.spel.mapper")
+public class Application {
+
+ public static void main(String[] args) {
+ SpringApplication.run(Application.class, args);
+ }
+
+}
\ No newline at end of file
diff --git a/samples/dynamic-spel-sample/src/main/java/com/baomidou/samples/spel/controller/UserController.java b/samples/dynamic-spel-sample/src/main/java/com/baomidou/samples/spel/controller/UserController.java
new file mode 100644
index 0000000..8c49eaa
--- /dev/null
+++ b/samples/dynamic-spel-sample/src/main/java/com/baomidou/samples/spel/controller/UserController.java
@@ -0,0 +1,29 @@
+package com.baomidou.samples.spel.controller;
+
+import com.baomidou.samples.spel.entity.User;
+import com.baomidou.samples.spel.service.UserService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import javax.servlet.http.HttpServletRequest;
+import java.util.List;
+
+@RestController
+public class UserController {
+ @Autowired
+ private UserService userService;
+
+ @GetMapping("/users")
+ public List usersFromSession(HttpServletRequest request) {
+ request.getSession().setAttribute("tenantName", "tenant1");
+ return userService.selectSpelBySession();
+ }
+
+ @GetMapping("/users/header")
+ public String usersFromHeader() {
+ userService.selectSpelByHeader();
+ return "success";
+ }
+
+}
diff --git a/samples/dynamic-spel-sample/src/main/java/com/baomidou/samples/spel/entity/User.java b/samples/dynamic-spel-sample/src/main/java/com/baomidou/samples/spel/entity/User.java
new file mode 100644
index 0000000..3a5f958
--- /dev/null
+++ b/samples/dynamic-spel-sample/src/main/java/com/baomidou/samples/spel/entity/User.java
@@ -0,0 +1,44 @@
+package com.baomidou.samples.spel.entity;
+
+public class User {
+
+ private Integer id;
+
+ private String name;
+
+ private Integer age;
+
+ private String tenantName;
+
+ public Integer getId() {
+ return id;
+ }
+
+ public void setId(Integer id) {
+ this.id = id;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public Integer getAge() {
+ return age;
+ }
+
+ public void setAge(Integer age) {
+ this.age = age;
+ }
+
+ public String getTenantName() {
+ return tenantName;
+ }
+
+ public void setTenantName(String tenantName) {
+ this.tenantName = tenantName;
+ }
+}
diff --git a/samples/dynamic-spel-sample/src/main/java/com/baomidou/samples/spel/mapper/UserMapper.java b/samples/dynamic-spel-sample/src/main/java/com/baomidou/samples/spel/mapper/UserMapper.java
new file mode 100644
index 0000000..ea3df74
--- /dev/null
+++ b/samples/dynamic-spel-sample/src/main/java/com/baomidou/samples/spel/mapper/UserMapper.java
@@ -0,0 +1,18 @@
+package com.baomidou.samples.spel.mapper;
+
+import com.baomidou.samples.spel.entity.User;
+import org.apache.ibatis.annotations.Insert;
+import org.apache.ibatis.annotations.Param;
+import org.apache.ibatis.annotations.Select;
+
+import java.util.List;
+
+//@DS("slave")这里可以使用但不建议,不要和service同时使用
+public interface UserMapper {
+
+ @Insert("INSERT INTO user (name,age) values (#{name},#{age})")
+ boolean addUser(@Param("name") String name, @Param("age") Integer age);
+
+ @Select("SELECT * FROM user")
+ List selectUsers();
+}
diff --git a/samples/dynamic-spel-sample/src/main/java/com/baomidou/samples/spel/service/UserService.java b/samples/dynamic-spel-sample/src/main/java/com/baomidou/samples/spel/service/UserService.java
new file mode 100644
index 0000000..19bb589
--- /dev/null
+++ b/samples/dynamic-spel-sample/src/main/java/com/baomidou/samples/spel/service/UserService.java
@@ -0,0 +1,17 @@
+package com.baomidou.samples.spel.service;
+
+
+import com.baomidou.samples.spel.entity.User;
+
+import java.util.List;
+
+public interface UserService {
+
+ List selectSpelBySession();
+
+ List selectSpelByHeader();
+
+ List selectSpelByKey(String tenantName);
+
+ List selecSpelByTenant(User user);
+}
diff --git a/samples/dynamic-spel-sample/src/main/java/com/baomidou/samples/spel/service/impl/UserServiceImpl.java b/samples/dynamic-spel-sample/src/main/java/com/baomidou/samples/spel/service/impl/UserServiceImpl.java
new file mode 100644
index 0000000..53901bb
--- /dev/null
+++ b/samples/dynamic-spel-sample/src/main/java/com/baomidou/samples/spel/service/impl/UserServiceImpl.java
@@ -0,0 +1,43 @@
+package com.baomidou.samples.spel.service.impl;
+
+
+import com.baomidou.dynamic.datasource.annotation.DS;
+import com.baomidou.samples.spel.entity.User;
+import com.baomidou.samples.spel.mapper.UserMapper;
+import com.baomidou.samples.spel.service.UserService;
+import org.springframework.stereotype.Service;
+
+import javax.annotation.Resource;
+import java.util.List;
+
+@Service
+@DS("slave")
+public class UserServiceImpl implements UserService {
+
+ @Resource
+ private UserMapper userMapper;
+
+ @Override
+ @DS("#session.tenantName")
+ public List selectSpelBySession() {
+ return userMapper.selectUsers();
+ }
+
+ @Override
+ @DS("#header.tenantName")
+ public List selectSpelByHeader() {
+ return userMapper.selectUsers();
+ }
+
+ @Override
+ @DS("#tenantName")
+ public List selectSpelByKey(String tenantName) {
+ return userMapper.selectUsers();
+ }
+
+ @Override
+ @DS("#user.tenantName")
+ public List selecSpelByTenant(User user) {
+ return userMapper.selectUsers();
+ }
+}
diff --git a/samples/dynamic-spel-sample/src/main/resources/application.yml b/samples/dynamic-spel-sample/src/main/resources/application.yml
new file mode 100644
index 0000000..bda2072
--- /dev/null
+++ b/samples/dynamic-spel-sample/src/main/resources/application.yml
@@ -0,0 +1,32 @@
+spring:
+ datasource:
+ dynamic:
+ datasource:
+ master:
+ username: sa
+ password: ""
+ url: jdbc:h2:mem:test
+ driver-class-name: org.h2.Driver
+ tenant1_1:
+ username: sa
+ password: ""
+ url: jdbc:h2:mem:test
+ driver-class-name: org.h2.Driver
+ tenant1_2:
+ username: sa
+ password: ""
+ url: jdbc:h2:mem:test
+ driver-class-name: org.h2.Driver
+ tenant2_1:
+ username: sa
+ password: ""
+ url: jdbc:h2:mem:test
+ driver-class-name: org.h2.Driver
+ tenant2_2:
+ username: sa
+ password: ""
+ url: jdbc:h2:mem:test
+ driver-class-name: org.h2.Driver
+logging:
+ level:
+ com.baomidou: debug
\ No newline at end of file
diff --git a/samples/dynamic-spel-sample/src/test/java/com/baomidou/samples/spel/test/ApplicationTest.java b/samples/dynamic-spel-sample/src/test/java/com/baomidou/samples/spel/test/ApplicationTest.java
new file mode 100644
index 0000000..173e225
--- /dev/null
+++ b/samples/dynamic-spel-sample/src/test/java/com/baomidou/samples/spel/test/ApplicationTest.java
@@ -0,0 +1,92 @@
+package com.baomidou.samples.spel.test;
+
+import com.baomidou.samples.spel.Application;
+import com.baomidou.samples.spel.entity.User;
+import com.baomidou.samples.spel.service.UserService;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.http.MediaType;
+import org.springframework.test.context.junit4.SpringRunner;
+import org.springframework.test.web.servlet.MockMvc;
+import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
+import org.springframework.test.web.servlet.setup.MockMvcBuilders;
+import org.springframework.web.context.WebApplicationContext;
+
+import javax.servlet.http.HttpSession;
+import javax.sql.DataSource;
+import java.sql.Connection;
+import java.sql.SQLException;
+
+import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
+
+@RunWith(SpringRunner.class)
+@SpringBootTest(classes = Application.class)
+public class ApplicationTest {
+
+ @Autowired
+ private WebApplicationContext wac;
+
+ @Autowired
+ private DataSource dataSource;
+
+ private MockMvc mockMvc;
+ @Autowired
+ private UserService userService;
+ @Autowired
+ private HttpSession session;
+
+ @Before
+ public void setup() {
+ this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).build();
+ }
+
+ @Before
+ public void beforeTest() {
+ try {
+ Connection connection = dataSource.getConnection();
+ connection.createStatement().execute("CREATE TABLE IF NOT EXISTS USER (\n" +
+ " id BIGINT(20) NOT NULL AUTO_INCREMENT,\n" +
+ " name VARCHAR(30) NULL DEFAULT NULL ,\n" +
+ " age INT(11) NULL DEFAULT NULL ,\n" +
+ " PRIMARY KEY (id)\n" +
+ ");");
+ connection.close();
+ } catch (SQLException e) {
+ e.printStackTrace();
+ }
+ }
+
+ @Test
+ public void selectSpelBySession() {
+ session.setAttribute("tenantName", "tenant1");
+ userService.selectSpelBySession();
+ }
+
+ @Test
+ public void selectSpelByHeader() throws Exception {
+ mockMvc.perform(MockMvcRequestBuilders.get("/users/header")
+ .contentType(MediaType.APPLICATION_FORM_URLENCODED)
+ .header("tenantName", "tenant1")
+ )
+ .andDo(print()).andExpect(status().isOk())
+ .andReturn().getResponse()
+ .getContentAsString();
+ }
+
+ @Test
+ public void selectSpelByKey() {
+ userService.selectSpelByKey("tenant1");
+ }
+
+ @Test
+ public void selecSpelByTenant() {
+ User user = new User();
+ user.setTenantName("tenant2");
+ userService.selecSpelByTenant(user);
+ }
+
+}
diff --git a/samples/pom.xml b/samples/pom.xml
new file mode 100644
index 0000000..c45c0b7
--- /dev/null
+++ b/samples/pom.xml
@@ -0,0 +1,71 @@
+
+
+ 4.0.0
+
+
+ org.springframework.boot
+ spring-boot-starter-parent
+ 2.1.0.RELEASE
+
+
+
+ com.baomidou
+ dynamic-datsource-samples
+ 1.0.0
+ pom
+
+
+ UTF-8
+ UTF-8
+ 1.8
+
+
+
+ dynamic-jdbc-template-sample
+ dynamic-mybatis-sample
+ dynamic-mybatisplus2-sample
+ dynamic-mybatisplus3-sample
+ dynamic-druid-mybatis-sample
+ dynamic-spel-sample
+ dynamic-nest-sample
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+
+
+ com.baomidou
+ dynamic-datasource-spring-boot-starter
+ 2.3.7
+
+
+ org.springframework.boot
+ spring-boot-starter-test
+ test
+
+
+ com.h2database
+ h2
+ 1.4.197
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+ 3.1
+
+ ${java.version}
+ ${java.version}
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/main/java/com/baomidou/dynamic/datasource/AbstractRoutingDataSource.java b/src/main/java/com/baomidou/dynamic/datasource/AbstractRoutingDataSource.java
new file mode 100644
index 0000000..b73e8aa
--- /dev/null
+++ b/src/main/java/com/baomidou/dynamic/datasource/AbstractRoutingDataSource.java
@@ -0,0 +1,63 @@
+/**
+ * Copyright © 2018 organization baomidou
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+package com.baomidou.dynamic.datasource;
+
+import org.springframework.jdbc.datasource.AbstractDataSource;
+
+import javax.sql.DataSource;
+import java.sql.Connection;
+import java.sql.SQLException;
+
+/**
+ * 抽象动态获取数据源
+ *
+ * @author TaoYu
+ * @since 2.2.0
+ */
+public abstract class AbstractRoutingDataSource extends AbstractDataSource {
+
+ /**
+ * 子类实现决定最终数据源
+ *
+ * @return 数据源
+ */
+ protected abstract DataSource determineDataSource();
+
+ @Override
+ public Connection getConnection() throws SQLException {
+ return determineDataSource().getConnection();
+ }
+
+ @Override
+ public Connection getConnection(String username, String password) throws SQLException {
+ return determineDataSource().getConnection(username, password);
+ }
+
+ @Override
+ @SuppressWarnings("unchecked")
+ public T unwrap(Class iface) throws SQLException {
+ if (iface.isInstance(this)) {
+ return (T) this;
+ }
+ return determineDataSource().unwrap(iface);
+ }
+
+ @Override
+ public boolean isWrapperFor(Class> iface) throws SQLException {
+ return (iface.isInstance(this) || determineDataSource().isWrapperFor(iface));
+ }
+}
diff --git a/src/main/java/com/baomidou/dynamic/datasource/DynamicDataSourceClassResolver.java b/src/main/java/com/baomidou/dynamic/datasource/DynamicDataSourceClassResolver.java
new file mode 100644
index 0000000..dcc62e5
--- /dev/null
+++ b/src/main/java/com/baomidou/dynamic/datasource/DynamicDataSourceClassResolver.java
@@ -0,0 +1,66 @@
+/**
+ * Copyright © 2018 organization baomidou
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+package com.baomidou.dynamic.datasource;
+
+import lombok.extern.slf4j.Slf4j;
+import org.aopalliance.intercept.MethodInvocation;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Proxy;
+
+/**
+ * 获取对mybatis-plus的支持
+ *
+ * @author TaoYu
+ * @since 2.3.0
+ */
+@Slf4j
+public class DynamicDataSourceClassResolver {
+
+ private boolean mpEnabled = false;
+
+ private Field mapperInterfaceField;
+
+ public DynamicDataSourceClassResolver() {
+ Class> proxyClass = null;
+ try {
+ proxyClass = Class.forName("com.baomidou.mybatisplus.core.override.PageMapperProxy");
+ } catch (ClassNotFoundException e) {
+ try {
+ proxyClass = Class.forName("org.apache.ibatis.binding.MapperProxy");
+ } catch (ClassNotFoundException e1) {
+ }
+ }
+ if (proxyClass != null) {
+ try {
+ mapperInterfaceField = proxyClass.getDeclaredField("mapperInterface");
+ mapperInterfaceField.setAccessible(true);
+ mpEnabled = true;
+ } catch (NoSuchFieldException e) {
+ e.printStackTrace();
+ }
+ }
+ }
+
+ public Class> targetClass(MethodInvocation invocation) throws IllegalAccessException {
+ if (mpEnabled) {
+ Object target = invocation.getThis();
+ return Proxy.isProxyClass(target.getClass()) ? (Class) mapperInterfaceField.get(Proxy.getInvocationHandler(target)) : target.getClass();
+ }
+ return invocation.getMethod().getDeclaringClass();
+ }
+}
diff --git a/src/main/java/com/baomidou/dynamic/datasource/DynamicDataSourceCreator.java b/src/main/java/com/baomidou/dynamic/datasource/DynamicDataSourceCreator.java
new file mode 100644
index 0000000..69363d2
--- /dev/null
+++ b/src/main/java/com/baomidou/dynamic/datasource/DynamicDataSourceCreator.java
@@ -0,0 +1,238 @@
+/**
+ * Copyright © 2018 organization baomidou
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+package com.baomidou.dynamic.datasource;
+
+import com.alibaba.druid.pool.DruidDataSource;
+import com.baomidou.dynamic.datasource.spring.boot.autoconfigure.DataSourceProperty;
+import com.baomidou.dynamic.datasource.spring.boot.autoconfigure.druid.DruidConfig;
+import com.zaxxer.hikari.HikariConfig;
+import com.zaxxer.hikari.HikariDataSource;
+import lombok.Setter;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.jdbc.datasource.lookup.JndiDataSourceLookup;
+
+import javax.sql.DataSource;
+import java.lang.reflect.Method;
+import java.sql.SQLException;
+
+/**
+ * 数据源创建器
+ *
+ * @author TaoYu
+ * @since 2.3.0
+ */
+@Slf4j
+public class DynamicDataSourceCreator {
+
+ /**
+ * DRUID数据源类
+ */
+ private static final String DRUID_DATASOURCE = "com.alibaba.druid.pool.DruidDataSource";
+ /**
+ * HikariCp数据源
+ */
+ private static final String HIKARI_DATASOURCE = "com.zaxxer.hikari.HikariDataSource";
+ /**
+ * JNDI数据源查找
+ */
+ private static final JndiDataSourceLookup JNDI_DATA_SOURCE_LOOKUP = new JndiDataSourceLookup();
+
+ private Method createMethod;
+ private Method typeMethod;
+ private Method urlMethod;
+ private Method usernameMethod;
+ private Method passwordMethod;
+ private Method driverClassNameMethod;
+ private Method buildMethod;
+
+ /**
+ * 是否存在druid
+ */
+ private Boolean druidExists = false;
+ /**
+ * 是否存在hikari
+ */
+ private Boolean hikariExists = false;
+
+ @Setter
+ private DruidConfig druidGlobalConfig;
+
+ @Setter
+ private HikariConfig globalHikariConfig;
+
+ public DynamicDataSourceCreator() {
+ Class> builderClass = null;
+ try {
+ builderClass = Class.forName("org.springframework.boot.jdbc.DataSourceBuilder");
+ } catch (Exception e) {
+ try {
+ builderClass = Class.forName("org.springframework.boot.autoconfigure.jdbc.DataSourceBuilder");
+ } catch (Exception e1) {
+ }
+ }
+ try {
+ createMethod = builderClass.getDeclaredMethod("create");
+ typeMethod = builderClass.getDeclaredMethod("type", Class.class);
+ urlMethod = builderClass.getDeclaredMethod("url", String.class);
+ usernameMethod = builderClass.getDeclaredMethod("username", String.class);
+ passwordMethod = builderClass.getDeclaredMethod("password", String.class);
+ driverClassNameMethod = builderClass.getDeclaredMethod("driverClassName", String.class);
+ buildMethod = builderClass.getDeclaredMethod("build");
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ try {
+ Class.forName(DRUID_DATASOURCE);
+ log.info("动态数据源-检测到druid存在,如配置中未指定type,druid会默认配置");
+ druidExists = true;
+ } catch (ClassNotFoundException e) {
+ }
+ try {
+ Class.forName(HIKARI_DATASOURCE);
+ hikariExists = true;
+ } catch (ClassNotFoundException e) {
+ }
+ }
+
+ /**
+ * 创建数据源
+ *
+ * @param dataSourceProperty 数据源信息
+ * @return 数据源
+ */
+ public DataSource createDataSource(DataSourceProperty dataSourceProperty) {
+ //如果是jndi数据源
+ String jndiName = dataSourceProperty.getJndiName();
+ if (jndiName != null && !jndiName.isEmpty()) {
+ return createJNDIDataSource(jndiName);
+ }
+ Class extends DataSource> type = dataSourceProperty.getType();
+ if (type == null) {
+ if (druidExists) {
+ return createDruidDataSource(dataSourceProperty);
+ } else if (hikariExists) {
+ return createHikariDataSource(dataSourceProperty);
+ }
+ } else if (DRUID_DATASOURCE.equals(type.getName())) {
+ return createDruidDataSource(dataSourceProperty);
+ } else if (HIKARI_DATASOURCE.equals(type.getName())) {
+ return createHikariDataSource(dataSourceProperty);
+ }
+ return createBasicDataSource(dataSourceProperty);
+ }
+
+ /**
+ * 创建基础数据源
+ *
+ * @param dataSourceProperty 数据源参数
+ * @return 数据源
+ */
+ public DataSource createBasicDataSource(DataSourceProperty dataSourceProperty) {
+ try {
+ Object o1 = createMethod.invoke(null);
+ Object o2 = typeMethod.invoke(o1, dataSourceProperty.getType());
+ Object o3 = urlMethod.invoke(o2, dataSourceProperty.getUrl());
+ Object o4 = usernameMethod.invoke(o3, dataSourceProperty.getUsername());
+ Object o5 = passwordMethod.invoke(o4, dataSourceProperty.getPassword());
+ Object o6 = driverClassNameMethod.invoke(o5, dataSourceProperty.getDriverClassName());
+ return (DataSource) buildMethod.invoke(o6);
+ } catch (Exception e) {
+ throw new RuntimeException("多数据源创建数据源失败");
+ }
+ }
+
+ /**
+ * 创建JNDI数据源
+ *
+ * @param jndiName jndi数据源名称
+ * @return 数据源
+ */
+ public DataSource createJNDIDataSource(String jndiName) {
+ return JNDI_DATA_SOURCE_LOOKUP.getDataSource(jndiName);
+ }
+
+ /**
+ * 创建DRUID数据源
+ *
+ * @param dataSourceProperty 数据源参数
+ * @return 数据源
+ */
+ public DataSource createDruidDataSource(DataSourceProperty dataSourceProperty) {
+ DruidDataSource dataSource = new DruidDataSource();
+ dataSource.setName(dataSourceProperty.getPollName());
+ dataSource.setUrl(dataSourceProperty.getUrl());
+ dataSource.setUsername(dataSourceProperty.getUsername());
+ dataSource.setPassword(dataSourceProperty.getPassword());
+ dataSource.setDriverClassName(dataSourceProperty.getDriverClassName());
+
+ DruidConfig config = dataSourceProperty.getDruid();
+ dataSource.configFromPropety(config.toProperties(druidGlobalConfig));
+
+ //设置druid内置properties不支持的的参数
+ Boolean testOnReturn = config.getTestOnReturn() == null ? druidGlobalConfig.getTestOnReturn() : config.getTestOnReturn();
+ if (testOnReturn != null && testOnReturn.equals(true)) {
+ dataSource.setTestOnReturn(true);
+ }
+ Integer validationQueryTimeout = config.getValidationQueryTimeout() == null ? druidGlobalConfig.getValidationQueryTimeout() : config.getValidationQueryTimeout();
+ if (validationQueryTimeout != null && !validationQueryTimeout.equals(-1)) {
+ dataSource.setValidationQueryTimeout(validationQueryTimeout);
+ }
+
+ Boolean sharePreparedStatements = config.getSharePreparedStatements() == null ? druidGlobalConfig.getSharePreparedStatements() : config.getSharePreparedStatements();
+ if (sharePreparedStatements != null && sharePreparedStatements.equals(true)) {
+ dataSource.setSharePreparedStatements(true);
+ }
+ Integer connectionErrorRetryAttempts = config.getConnectionErrorRetryAttempts() == null ? druidGlobalConfig.getConnectionErrorRetryAttempts() : config.getConnectionErrorRetryAttempts();
+ if (connectionErrorRetryAttempts != null && !connectionErrorRetryAttempts.equals(1)) {
+ dataSource.setConnectionErrorRetryAttempts(connectionErrorRetryAttempts);
+ }
+ Boolean breakAfterAcquireFailure = config.getBreakAfterAcquireFailure() == null ? druidGlobalConfig.getBreakAfterAcquireFailure() : config.getBreakAfterAcquireFailure();
+ if (breakAfterAcquireFailure != null && breakAfterAcquireFailure.equals(true)) {
+ dataSource.setBreakAfterAcquireFailure(true);
+ }
+ try {
+ dataSource.init();
+ } catch (SQLException e) {
+ log.error("druid数据源启动失败", e);
+ }
+ return dataSource;
+ }
+
+ /**
+ * 创建Hikari数据源
+ *
+ * @param dataSourceProperty 数据源参数
+ * @return 数据源
+ * @author 离世庭院
+ */
+ public DataSource createHikariDataSource(DataSourceProperty dataSourceProperty) {
+ HikariConfig hikariConfig = dataSourceProperty.getHikari();
+ if (hikariConfig == null) {
+ //自己没设置就copy全局参数
+ hikariConfig.copyState(globalHikariConfig);
+ }
+ hikariConfig.setJdbcUrl(dataSourceProperty.getUrl());
+ hikariConfig.setUsername(dataSourceProperty.getUsername());
+ hikariConfig.setPassword(dataSourceProperty.getPassword());
+ hikariConfig.setDriverClassName(dataSourceProperty.getDriverClassName());
+ //暂时不支持设置监控
+// hikariConfig.setMetricRegistry(metricRegistry);
+// hikariConfig.setHealthCheckRegistry(healthCheckRegistry);
+ hikariConfig.setPoolName(dataSourceProperty.getPollName());
+ return new HikariDataSource(hikariConfig);
+ }
+}
diff --git a/src/main/java/com/baomidou/dynamic/datasource/DynamicGroupDataSource.java b/src/main/java/com/baomidou/dynamic/datasource/DynamicGroupDataSource.java
new file mode 100644
index 0000000..844cd58
--- /dev/null
+++ b/src/main/java/com/baomidou/dynamic/datasource/DynamicGroupDataSource.java
@@ -0,0 +1,70 @@
+/**
+ * Copyright © 2018 organization baomidou
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+package com.baomidou.dynamic.datasource;
+
+import com.baomidou.dynamic.datasource.strategy.DynamicDataSourceStrategy;
+import lombok.Data;
+
+import javax.sql.DataSource;
+import java.util.LinkedList;
+import java.util.List;
+
+/**
+ * 分组数据源
+ *
+ * @author TaoYu Kanyuxia
+ * @since 2.0.0
+ */
+@Data
+public class DynamicGroupDataSource {
+
+ /**
+ * 组名
+ */
+ private String groupName;
+
+ /**
+ * 数据源切换策略
+ */
+ private DynamicDataSourceStrategy dynamicDataSourceStrategy;
+
+ /**
+ * 当前组下所有数据源
+ */
+ private List dataSources = new LinkedList<>();
+
+ public DynamicGroupDataSource(String groupName, DynamicDataSourceStrategy dynamicDataSourceStrategy) {
+ this.groupName = groupName;
+ this.dynamicDataSourceStrategy = dynamicDataSourceStrategy;
+ }
+
+ public void addDatasource(DataSource dataSource) {
+ dataSources.add(dataSource);
+ }
+
+ public void removeDatasource(DataSource dataSource) {
+ dataSources.remove(dataSource);
+ }
+
+ public DataSource determineDataSource() {
+ return dynamicDataSourceStrategy.determineDataSource(dataSources);
+ }
+
+ public int size() {
+ return dataSources.size();
+ }
+}
diff --git a/src/main/java/com/baomidou/dynamic/datasource/DynamicRoutingDataSource.java b/src/main/java/com/baomidou/dynamic/datasource/DynamicRoutingDataSource.java
new file mode 100644
index 0000000..cced38c
--- /dev/null
+++ b/src/main/java/com/baomidou/dynamic/datasource/DynamicRoutingDataSource.java
@@ -0,0 +1,167 @@
+/**
+ * Copyright © 2018 organization baomidou
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+package com.baomidou.dynamic.datasource;
+
+import com.baomidou.dynamic.datasource.provider.DynamicDataSourceProvider;
+import com.baomidou.dynamic.datasource.strategy.DynamicDataSourceStrategy;
+import com.baomidou.dynamic.datasource.toolkit.DynamicDataSourceContextHolder;
+import lombok.Setter;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.util.StringUtils;
+
+import javax.sql.DataSource;
+import java.util.LinkedHashMap;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+/**
+ * 核心动态数据源组件
+ *
+ * @author TaoYu Kanyuxia
+ * @since 1.0.0
+ */
+@Slf4j
+public class DynamicRoutingDataSource extends AbstractRoutingDataSource {
+
+
+ private static final String UNDERLINE = "_";
+ @Setter
+ protected DynamicDataSourceProvider provider;
+ @Setter
+ protected Class extends DynamicDataSourceStrategy> strategy;
+ @Setter
+ protected String primary;
+ /**
+ * 所有数据库
+ */
+ private Map dataSourceMap = new LinkedHashMap<>();
+ /**
+ * 分组数据库
+ */
+ private Map groupDataSources = new ConcurrentHashMap<>();
+
+ @Override
+ public DataSource determineDataSource() {
+ return getDataSource(DynamicDataSourceContextHolder.getDataSourceLookupKey());
+ }
+
+ private DataSource determinePrimaryDataSource() {
+ log.debug("从默认数据源中返回数据");
+ return groupDataSources.containsKey(primary) ? groupDataSources.get(primary).determineDataSource() : dataSourceMap.get(primary);
+ }
+
+ /**
+ * 获取当前所有的数据源
+ *
+ * @return 当前所有数据源
+ */
+ public Map getCurrentDataSources() {
+ return dataSourceMap;
+ }
+
+ /**
+ * 获取的当前所有的分组数据源
+ *
+ * @return 当前所有的分组数据源
+ */
+ public Map getCurrentGroupDataSources() {
+ return groupDataSources;
+ }
+
+ /**
+ * 获取数据源
+ *
+ * @param ds 数据源名称
+ * @return 数据源
+ */
+ public DataSource getDataSource(String ds) {
+ if (StringUtils.isEmpty(ds)) {
+ return determinePrimaryDataSource();
+ } else if (!groupDataSources.isEmpty() && groupDataSources.containsKey(ds)) {
+ log.debug("从 {} 组数据源中返回数据源", ds);
+ return groupDataSources.get(ds).determineDataSource();
+ } else if (dataSourceMap.containsKey(ds)) {
+ log.debug("从 {} 单数据源中返回数据源", ds);
+ return dataSourceMap.get(ds);
+ }
+ return determinePrimaryDataSource();
+ }
+
+ /**
+ * 添加数据源
+ *
+ * @param ds 数据源名称
+ * @param dataSource 数据源
+ */
+ public synchronized void addDataSource(String ds, DataSource dataSource) {
+ dataSourceMap.put(ds, dataSource);
+ if (ds.contains(UNDERLINE)) {
+ String group = ds.split(UNDERLINE)[0];
+ if (groupDataSources.containsKey(group)) {
+ groupDataSources.get(group).addDatasource(dataSource);
+ } else {
+ try {
+ DynamicGroupDataSource groupDatasource = new DynamicGroupDataSource(group, strategy.newInstance());
+ groupDatasource.addDatasource(dataSource);
+ groupDataSources.put(group, groupDatasource);
+ } catch (Exception e) {
+ log.error("添加数据源失败", e);
+ dataSourceMap.remove(ds);
+ }
+ }
+ }
+ log.info("动态数据源-加载 {} 成功", ds);
+ }
+
+ /**
+ * 删除数据源
+ *
+ * @param ds 数据源名称
+ */
+ public synchronized void removeDataSource(String ds) {
+ if (dataSourceMap.containsKey(ds)) {
+ DataSource dataSource = dataSourceMap.get(ds);
+ dataSourceMap.remove(ds);
+ if (ds.contains(UNDERLINE)) {
+ String group = ds.split(UNDERLINE)[0];
+ if (groupDataSources.containsKey(group)) {
+ groupDataSources.get(group).removeDatasource(dataSource);
+ }
+ }
+ log.info("动态数据源-删除 {} 成功", ds);
+ } else {
+ log.warn("动态数据源-未找到 {} 数据源");
+ }
+ }
+
+ public void init() {
+ Map dataSources = provider.loadDataSources();
+ log.info("初始共加载 {} 个数据源", dataSources.size());
+ //添加并分组数据源
+ for (Map.Entry dsItem : dataSources.entrySet()) {
+ addDataSource(dsItem.getKey(), dsItem.getValue());
+ }
+ //检测默认数据源设置
+ if (groupDataSources.containsKey(primary)) {
+ log.info("当前的默认数据源是组数据源,组名为 {} ,其下有 {} 个数据源", primary, groupDataSources.size());
+ } else if (dataSourceMap.containsKey(primary)) {
+ log.info("当前的默认数据源是单数据源,数据源名为 {}", primary);
+ } else {
+ throw new RuntimeException("请检查primary默认数据库设置");
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/baomidou/dynamic/datasource/annotation/DS.java b/src/main/java/com/baomidou/dynamic/datasource/annotation/DS.java
new file mode 100644
index 0000000..dc91b32
--- /dev/null
+++ b/src/main/java/com/baomidou/dynamic/datasource/annotation/DS.java
@@ -0,0 +1,39 @@
+/**
+ * Copyright © 2018 organization baomidou
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+package com.baomidou.dynamic.datasource.annotation;
+
+
+import java.lang.annotation.*;
+
+/**
+ * 注解在类上或方法上来切换数据源
+ *
+ * @author TaoYu Kanyuxia
+ * @since 1.0.0
+ */
+@Target({ElementType.TYPE, ElementType.METHOD})
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+public @interface DS {
+
+ /**
+ * 组名或者具体数据源名称或者spel参数(#开头)
+ *
+ * @return 数据源名称
+ */
+ String value();
+}
\ No newline at end of file
diff --git a/src/main/java/com/baomidou/dynamic/datasource/aop/DynamicDataSourceAnnotationAdvisor.java b/src/main/java/com/baomidou/dynamic/datasource/aop/DynamicDataSourceAnnotationAdvisor.java
new file mode 100644
index 0000000..2af6bab
--- /dev/null
+++ b/src/main/java/com/baomidou/dynamic/datasource/aop/DynamicDataSourceAnnotationAdvisor.java
@@ -0,0 +1,69 @@
+/**
+ * Copyright © 2018 organization baomidou
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+package com.baomidou.dynamic.datasource.aop;
+
+import com.baomidou.dynamic.datasource.annotation.DS;
+import lombok.NonNull;
+import org.aopalliance.aop.Advice;
+import org.springframework.aop.Pointcut;
+import org.springframework.aop.support.AbstractPointcutAdvisor;
+import org.springframework.aop.support.ComposablePointcut;
+import org.springframework.aop.support.annotation.AnnotationMatchingPointcut;
+import org.springframework.beans.BeansException;
+import org.springframework.beans.factory.BeanFactory;
+import org.springframework.beans.factory.BeanFactoryAware;
+
+/**
+ * 动态数据源AOP织入
+ *
+ * @author TaoYu
+ * @since 1.2.0
+ */
+public class DynamicDataSourceAnnotationAdvisor extends AbstractPointcutAdvisor implements BeanFactoryAware {
+
+ private Advice advice;
+
+ private Pointcut pointcut;
+
+ public DynamicDataSourceAnnotationAdvisor(@NonNull DynamicDataSourceAnnotationInterceptor dynamicDataSourceAnnotationInterceptor) {
+ this.advice = dynamicDataSourceAnnotationInterceptor;
+ this.pointcut = buildPointcut();
+ }
+
+ @Override
+ public Pointcut getPointcut() {
+ return this.pointcut;
+ }
+
+ @Override
+ public Advice getAdvice() {
+ return this.advice;
+ }
+
+ @Override
+ public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
+ if (this.advice instanceof BeanFactoryAware) {
+ ((BeanFactoryAware) this.advice).setBeanFactory(beanFactory);
+ }
+ }
+
+ private Pointcut buildPointcut() {
+ Pointcut cpc = new AnnotationMatchingPointcut(DS.class, true);
+ Pointcut mpc = AnnotationMatchingPointcut.forMethodAnnotation(DS.class);
+ return new ComposablePointcut(cpc).union(mpc);
+ }
+}
diff --git a/src/main/java/com/baomidou/dynamic/datasource/aop/DynamicDataSourceAnnotationInterceptor.java b/src/main/java/com/baomidou/dynamic/datasource/aop/DynamicDataSourceAnnotationInterceptor.java
new file mode 100644
index 0000000..4a7229d
--- /dev/null
+++ b/src/main/java/com/baomidou/dynamic/datasource/aop/DynamicDataSourceAnnotationInterceptor.java
@@ -0,0 +1,74 @@
+/**
+ * Copyright © 2018 organization baomidou
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+package com.baomidou.dynamic.datasource.aop;
+
+import com.baomidou.dynamic.datasource.DynamicDataSourceClassResolver;
+import com.baomidou.dynamic.datasource.annotation.DS;
+import com.baomidou.dynamic.datasource.spel.DynamicDataSourceSpelParser;
+import com.baomidou.dynamic.datasource.spel.DynamicDataSourceSpelResolver;
+import com.baomidou.dynamic.datasource.toolkit.DynamicDataSourceContextHolder;
+import lombok.Setter;
+import org.aopalliance.intercept.MethodInterceptor;
+import org.aopalliance.intercept.MethodInvocation;
+import org.springframework.core.annotation.AnnotationUtils;
+
+import java.lang.reflect.Method;
+
+/**
+ * 动态数据源AOP核心拦截器
+ *
+ * @author TaoYu
+ * @since 1.2.0
+ */
+public class DynamicDataSourceAnnotationInterceptor implements MethodInterceptor {
+
+ /**
+ * SPEL参数标识
+ */
+ private static final String SPEL_PREFIX = "#";
+
+ @Setter
+ private DynamicDataSourceSpelResolver dynamicDataSourceSpelResolver;
+
+ @Setter
+ private DynamicDataSourceSpelParser dynamicDataSourceSpelParser;
+
+ private DynamicDataSourceClassResolver dynamicDataSourceClassResolver = new DynamicDataSourceClassResolver();
+
+ @Override
+ public Object invoke(MethodInvocation invocation) throws Throwable {
+ try {
+ DynamicDataSourceContextHolder.setDataSourceLookupKey(determineDatasource(invocation));
+ return invocation.proceed();
+ } finally {
+ DynamicDataSourceContextHolder.clearDataSourceLookupKey();
+ }
+ }
+
+ private String determineDatasource(MethodInvocation invocation) throws Throwable {
+ Method method = invocation.getMethod();
+ Class> declaringClass = dynamicDataSourceClassResolver.targetClass(invocation);
+ DS ds = method.isAnnotationPresent(DS.class) ? method.getAnnotation(DS.class)
+ : AnnotationUtils.findAnnotation(declaringClass, DS.class);
+ String value = ds.value();
+ if (!value.isEmpty() && value.startsWith(SPEL_PREFIX)) {
+ String spelValue = dynamicDataSourceSpelParser.parse(invocation, value);
+ return dynamicDataSourceSpelResolver.resolve(spelValue);
+ }
+ return value;
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/baomidou/dynamic/datasource/provider/AbstractJdbcDataSourceProvider.java b/src/main/java/com/baomidou/dynamic/datasource/provider/AbstractJdbcDataSourceProvider.java
new file mode 100644
index 0000000..7fd18aa
--- /dev/null
+++ b/src/main/java/com/baomidou/dynamic/datasource/provider/AbstractJdbcDataSourceProvider.java
@@ -0,0 +1,109 @@
+/**
+ * Copyright © 2018 organization baomidou
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+package com.baomidou.dynamic.datasource.provider;
+
+import com.baomidou.dynamic.datasource.DynamicDataSourceCreator;
+import com.baomidou.dynamic.datasource.spring.boot.autoconfigure.DataSourceProperty;
+import com.baomidou.dynamic.datasource.spring.boot.autoconfigure.DynamicDataSourceProperties;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.jdbc.support.JdbcUtils;
+
+import javax.sql.DataSource;
+import java.sql.Connection;
+import java.sql.DriverManager;
+import java.sql.SQLException;
+import java.sql.Statement;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * JDBC数据源提供者(抽象)
+ *
+ * @author TaoYu
+ * @since 2.1.2
+ */
+@Slf4j
+public abstract class AbstractJdbcDataSourceProvider implements DynamicDataSourceProvider {
+
+ @Autowired(required = false)
+ protected DynamicDataSourceProperties dynamicDataSourceProperties;
+
+ @Autowired
+ private DynamicDataSourceCreator dynamicDataSourceCreator;
+
+ /**
+ * JDBC driver
+ */
+ private String driverClassName;
+ /**
+ * JDBC url 地址
+ */
+ private String url;
+ /**
+ * JDBC 用户名
+ */
+ private String username;
+ /**
+ * JDBC 密码
+ */
+ private String password;
+
+ public AbstractJdbcDataSourceProvider(String driverClassName, String url, String username, String password) {
+ this.driverClassName = driverClassName;
+ this.url = url;
+ this.username = username;
+ this.password = password;
+ }
+
+ @Override
+ public Map loadDataSources() {
+ Connection conn = null;
+ Statement stmt = null;
+ try {
+ Class.forName(driverClassName);
+ log.info("成功加载数据库驱动程序");
+ conn = DriverManager.getConnection(url, username, password);
+ log.info("成功获取数据库连接");
+ stmt = conn.createStatement();
+ Map dataSourcePropertiesMap = executeStmt(stmt);
+ Map dataSourceMap = new HashMap<>(dataSourcePropertiesMap.size());
+ for (Map.Entry item : dataSourcePropertiesMap.entrySet()) {
+ String pollName = item.getKey();
+ DataSourceProperty dataSourceProperty = item.getValue();
+ dataSourceProperty.setPollName(pollName);
+ dataSourceMap.put(pollName, dynamicDataSourceCreator.createDataSource(dataSourceProperty));
+ }
+ return dataSourceMap;
+ } catch (Exception e) {
+ e.printStackTrace();
+ } finally {
+ JdbcUtils.closeConnection(conn);
+ JdbcUtils.closeStatement(stmt);
+ }
+ return null;
+ }
+
+ /**
+ * 执行语句获得数据源参数
+ *
+ * @param statement 语句
+ * @return 数据源参数
+ * @throws SQLException sql异常
+ */
+ protected abstract Map executeStmt(Statement statement) throws SQLException;
+}
diff --git a/src/main/java/com/baomidou/dynamic/datasource/provider/DynamicDataSourceProvider.java b/src/main/java/com/baomidou/dynamic/datasource/provider/DynamicDataSourceProvider.java
new file mode 100644
index 0000000..70d8dd2
--- /dev/null
+++ b/src/main/java/com/baomidou/dynamic/datasource/provider/DynamicDataSourceProvider.java
@@ -0,0 +1,39 @@
+/**
+ * Copyright © 2018 organization baomidou
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+package com.baomidou.dynamic.datasource.provider;
+
+import javax.sql.DataSource;
+import java.util.Map;
+
+/**
+ * 多数据源加载接口,默认的实现为从yml信息中加载所有数据源
+ * 你可以自己实现从其他地方加载所有数据源
+ *
+ * @author TaoYu Kanyuxia
+ * @see YmlDynamicDataSourceProvider
+ * @see AbstractJdbcDataSourceProvider
+ * @since 1.0.0
+ */
+public interface DynamicDataSourceProvider {
+
+ /**
+ * 加载所有数据源
+ *
+ * @return 所有数据源,key为数据源名称
+ */
+ Map loadDataSources();
+}
diff --git a/src/main/java/com/baomidou/dynamic/datasource/provider/YmlDynamicDataSourceProvider.java b/src/main/java/com/baomidou/dynamic/datasource/provider/YmlDynamicDataSourceProvider.java
new file mode 100644
index 0000000..3a195f3
--- /dev/null
+++ b/src/main/java/com/baomidou/dynamic/datasource/provider/YmlDynamicDataSourceProvider.java
@@ -0,0 +1,63 @@
+/**
+ * Copyright © 2018 organization baomidou
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+package com.baomidou.dynamic.datasource.provider;
+
+import com.baomidou.dynamic.datasource.DynamicDataSourceCreator;
+import com.baomidou.dynamic.datasource.spring.boot.autoconfigure.DataSourceProperty;
+import com.baomidou.dynamic.datasource.spring.boot.autoconfigure.DynamicDataSourceProperties;
+import lombok.extern.slf4j.Slf4j;
+
+import javax.sql.DataSource;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * YML数据源提供者
+ *
+ * @author TaoYu Kanyuxia
+ * @since 1.0.0
+ */
+@Slf4j
+public class YmlDynamicDataSourceProvider implements DynamicDataSourceProvider {
+
+ /**
+ * 多数据源参数
+ */
+ private DynamicDataSourceProperties properties;
+ /**
+ * 多数据源创建器
+ */
+ private DynamicDataSourceCreator dynamicDataSourceCreator;
+
+ public YmlDynamicDataSourceProvider(DynamicDataSourceProperties properties, DynamicDataSourceCreator dynamicDataSourceCreator) {
+ this.properties = properties;
+ this.dynamicDataSourceCreator = dynamicDataSourceCreator;
+ }
+
+ @Override
+ public Map loadDataSources() {
+ Map dataSourcePropertiesMap = properties.getDatasource();
+ Map dataSourceMap = new HashMap<>(dataSourcePropertiesMap.size());
+ for (Map.Entry item : dataSourcePropertiesMap.entrySet()) {
+ String pollName = item.getKey();
+ DataSourceProperty dataSourceProperty = item.getValue();
+ dataSourceProperty.setPollName(pollName);
+ dataSourceMap.put(pollName, dynamicDataSourceCreator.createDataSource(dataSourceProperty));
+ }
+ return dataSourceMap;
+ }
+}
diff --git a/src/main/java/com/baomidou/dynamic/datasource/spel/DefaultDynamicDataSourceSpelParser.java b/src/main/java/com/baomidou/dynamic/datasource/spel/DefaultDynamicDataSourceSpelParser.java
new file mode 100644
index 0000000..0801f2e
--- /dev/null
+++ b/src/main/java/com/baomidou/dynamic/datasource/spel/DefaultDynamicDataSourceSpelParser.java
@@ -0,0 +1,80 @@
+/**
+ * Copyright © 2018 organization baomidou
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+package com.baomidou.dynamic.datasource.spel;
+
+import org.aopalliance.intercept.MethodInvocation;
+import org.springframework.context.expression.MethodBasedEvaluationContext;
+import org.springframework.core.DefaultParameterNameDiscoverer;
+import org.springframework.core.ParameterNameDiscoverer;
+import org.springframework.expression.EvaluationContext;
+import org.springframework.expression.ExpressionParser;
+import org.springframework.expression.spel.standard.SpelExpressionParser;
+import org.springframework.web.context.request.RequestContextHolder;
+import org.springframework.web.context.request.ServletRequestAttributes;
+
+import javax.servlet.http.HttpServletRequest;
+import java.lang.reflect.Method;
+
+/**
+ * 动态数据源Spel解析器
+ *
+ * @author TaoYu
+ * @since 2.3.0
+ */
+public class DefaultDynamicDataSourceSpelParser implements DynamicDataSourceSpelParser {
+
+ /**
+ * 参数发现器
+ */
+ private static final ParameterNameDiscoverer NAME_DISCOVERER = new DefaultParameterNameDiscoverer();
+ /**
+ * Express语法解析器
+ */
+ private static final ExpressionParser PARSER = new SpelExpressionParser();
+ /**
+ * session开头
+ */
+ private static final String SESSION_PREFIX = "#session";
+ /**
+ * header开头
+ */
+ private static final String HEADER_PREFIX = "#header";
+
+
+ /**
+ * 解析多数据源spel的参数
+ *
+ * @param invocation 动态方法执行器
+ * @param key 需要解析的key
+ * @return 解析后的值
+ */
+ @Override
+ public String parse(MethodInvocation invocation, String key) {
+ if (key.startsWith(SESSION_PREFIX)) {
+ HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
+ return request.getSession().getAttribute(key.substring(9)).toString();
+ } else if (key.startsWith(HEADER_PREFIX)) {
+ HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
+ return request.getHeader(key.substring(8));
+ } else {
+ Method method = invocation.getMethod();
+ Object[] arguments = invocation.getArguments();
+ EvaluationContext context = new MethodBasedEvaluationContext(null, method, arguments, NAME_DISCOVERER);
+ return PARSER.parseExpression(key).getValue(context).toString();
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/baomidou/dynamic/datasource/spel/DefaultDynamicDataSourceSpelResolver.java b/src/main/java/com/baomidou/dynamic/datasource/spel/DefaultDynamicDataSourceSpelResolver.java
new file mode 100644
index 0000000..e57174d
--- /dev/null
+++ b/src/main/java/com/baomidou/dynamic/datasource/spel/DefaultDynamicDataSourceSpelResolver.java
@@ -0,0 +1,32 @@
+/**
+ * Copyright © 2018 organization baomidou
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+package com.baomidou.dynamic.datasource.spel;
+
+/**
+ * 默认的spel参数处理器
+ * 直接返回 spel处理后的参数
+ *
+ * @author TaoYu
+ * @since 2.3.0
+ */
+public class DefaultDynamicDataSourceSpelResolver implements DynamicDataSourceSpelResolver {
+
+ @Override
+ public String resolve(String spelValue) {
+ return spelValue;
+ }
+}
diff --git a/src/main/java/com/baomidou/dynamic/datasource/spel/DynamicDataSourceSpelParser.java b/src/main/java/com/baomidou/dynamic/datasource/spel/DynamicDataSourceSpelParser.java
new file mode 100644
index 0000000..42b8cf6
--- /dev/null
+++ b/src/main/java/com/baomidou/dynamic/datasource/spel/DynamicDataSourceSpelParser.java
@@ -0,0 +1,37 @@
+/**
+ * Copyright © 2018 organization baomidou
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+package com.baomidou.dynamic.datasource.spel;
+
+import org.aopalliance.intercept.MethodInvocation;
+
+/**
+ * 动态数据源SPEL解析器
+ *
+ * @author TaoYu
+ * @since 2.3.3
+ */
+public interface DynamicDataSourceSpelParser {
+
+ /**
+ * 解析SPEL
+ *
+ * @param invocation 动态代理方法对象
+ * @param key ds的值
+ * @return 解析SPEL后获取的数据源名称
+ */
+ String parse(MethodInvocation invocation, String key);
+}
diff --git a/src/main/java/com/baomidou/dynamic/datasource/spel/DynamicDataSourceSpelResolver.java b/src/main/java/com/baomidou/dynamic/datasource/spel/DynamicDataSourceSpelResolver.java
new file mode 100644
index 0000000..3d2af12
--- /dev/null
+++ b/src/main/java/com/baomidou/dynamic/datasource/spel/DynamicDataSourceSpelResolver.java
@@ -0,0 +1,34 @@
+/**
+ * Copyright © 2018 organization baomidou
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+package com.baomidou.dynamic.datasource.spel;
+
+/**
+ * 动态数据源SPEL处理器
+ *
+ * @author TaoYu
+ * @since 2.3.0
+ */
+public interface DynamicDataSourceSpelResolver {
+
+ /**
+ * 处理spel解析后的参数
+ *
+ * @param spelValue spel参数
+ * @return 返回数据源名称
+ */
+ String resolve(String spelValue);
+}
diff --git a/src/main/java/com/baomidou/dynamic/datasource/spring/boot/autoconfigure/DataSourceProperty.java b/src/main/java/com/baomidou/dynamic/datasource/spring/boot/autoconfigure/DataSourceProperty.java
new file mode 100644
index 0000000..5081037
--- /dev/null
+++ b/src/main/java/com/baomidou/dynamic/datasource/spring/boot/autoconfigure/DataSourceProperty.java
@@ -0,0 +1,74 @@
+/**
+ * Copyright © 2018 organization baomidou
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+package com.baomidou.dynamic.datasource.spring.boot.autoconfigure;
+
+import com.baomidou.dynamic.datasource.spring.boot.autoconfigure.druid.DruidConfig;
+import com.zaxxer.hikari.HikariConfig;
+import lombok.Data;
+import lombok.experimental.Accessors;
+import org.springframework.boot.context.properties.NestedConfigurationProperty;
+
+import javax.sql.DataSource;
+
+/**
+ * @author TaoYu
+ * @since 1.2.0
+ */
+@Data
+@Accessors(chain = true)
+public class DataSourceProperty {
+
+ /**
+ * 连接池名称(只是一个名称标识)
+ * 默认是配置文件上的名称
+ */
+ private String pollName;
+ /**
+ * 连接池类型,如果不设置自动查找 Druid > HikariCp
+ */
+ private Class extends DataSource> type;
+ /**
+ * JDBC driver
+ */
+ private String driverClassName;
+ /**
+ * JDBC url 地址
+ */
+ private String url;
+ /**
+ * JDBC 用户名
+ */
+ private String username;
+ /**
+ * JDBC 密码
+ */
+ private String password;
+ /**
+ * jndi数据源名称(设置即表示启用)
+ */
+ private String jndiName;
+ /**
+ * Druid参数配置
+ */
+ @NestedConfigurationProperty
+ private DruidConfig druid = new DruidConfig();
+ /**
+ * HikariCp参数配置
+ */
+ @NestedConfigurationProperty
+ private HikariConfig hikari = new HikariConfig();
+}
diff --git a/src/main/java/com/baomidou/dynamic/datasource/spring/boot/autoconfigure/DynamicDataSourceAutoConfiguration.java b/src/main/java/com/baomidou/dynamic/datasource/spring/boot/autoconfigure/DynamicDataSourceAutoConfiguration.java
new file mode 100644
index 0000000..08fa122
--- /dev/null
+++ b/src/main/java/com/baomidou/dynamic/datasource/spring/boot/autoconfigure/DynamicDataSourceAutoConfiguration.java
@@ -0,0 +1,120 @@
+/**
+ * Copyright © 2018 organization baomidou
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+package com.baomidou.dynamic.datasource.spring.boot.autoconfigure;
+
+import com.baomidou.dynamic.datasource.DynamicDataSourceCreator;
+import com.baomidou.dynamic.datasource.DynamicRoutingDataSource;
+import com.baomidou.dynamic.datasource.aop.DynamicDataSourceAnnotationAdvisor;
+import com.baomidou.dynamic.datasource.aop.DynamicDataSourceAnnotationInterceptor;
+import com.baomidou.dynamic.datasource.provider.DynamicDataSourceProvider;
+import com.baomidou.dynamic.datasource.provider.YmlDynamicDataSourceProvider;
+import com.baomidou.dynamic.datasource.spel.DefaultDynamicDataSourceSpelParser;
+import com.baomidou.dynamic.datasource.spel.DefaultDynamicDataSourceSpelResolver;
+import com.baomidou.dynamic.datasource.spel.DynamicDataSourceSpelParser;
+import com.baomidou.dynamic.datasource.spel.DynamicDataSourceSpelResolver;
+import com.baomidou.dynamic.datasource.spring.boot.autoconfigure.druid.DruidDynamicDataSourceConfiguration;
+import com.baomidou.dynamic.datasource.strategy.DynamicDataSourceStrategy;
+import com.p6spy.engine.spy.P6DataSource;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.autoconfigure.AutoConfigureBefore;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
+import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
+import org.springframework.boot.context.properties.EnableConfigurationProperties;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.Import;
+
+import javax.sql.DataSource;
+
+/**
+ * 动态数据源核心自动配置类
+ *
+ * @author TaoYu Kanyuxia
+ * @see DynamicDataSourceProvider
+ * @see DynamicDataSourceStrategy
+ * @see DynamicRoutingDataSource
+ * @since 1.0.0
+ */
+@Slf4j
+@Configuration
+@EnableConfigurationProperties(DynamicDataSourceProperties.class)
+@AutoConfigureBefore(DataSourceAutoConfiguration.class)
+@Import(DruidDynamicDataSourceConfiguration.class)
+public class DynamicDataSourceAutoConfiguration {
+
+ @Autowired
+ private DynamicDataSourceProperties properties;
+
+ @Bean
+ @ConditionalOnMissingBean
+ public DynamicDataSourceProvider dynamicDataSourceProvider(DynamicDataSourceCreator dynamicDataSourceCreator) {
+ return new YmlDynamicDataSourceProvider(properties, dynamicDataSourceCreator);
+ }
+
+ @Bean
+ @ConditionalOnMissingBean
+ public DynamicDataSourceCreator dynamicDataSourceCreator() {
+ DynamicDataSourceCreator dynamicDataSourceCreator = new DynamicDataSourceCreator();
+ dynamicDataSourceCreator.setDruidGlobalConfig(properties.getDruid());
+ dynamicDataSourceCreator.setGlobalHikariConfig(properties.getHikari());
+ return dynamicDataSourceCreator;
+ }
+
+ @Bean
+ @ConditionalOnMissingBean
+ public DataSource dataSource(DynamicDataSourceProvider dynamicDataSourceProvider) {
+ DynamicRoutingDataSource dataSource = new DynamicRoutingDataSource();
+ dataSource.setPrimary(properties.getPrimary());
+ dataSource.setStrategy(properties.getStrategy());
+ dataSource.setProvider(dynamicDataSourceProvider);
+ dataSource.init();
+ if (properties.getP6spy()) {
+ try {
+ Class.forName("com.p6spy.engine.spy.P6DataSource");
+ log.info("动态数据源-关联p6sy成功");
+ return new P6DataSource(dataSource);
+ } catch (Exception e) {
+ log.warn("多数据源启动器开启了p6spy但并未引入相关依赖");
+ }
+ }
+ return dataSource;
+ }
+
+ @Bean
+ @ConditionalOnMissingBean
+ public DynamicDataSourceAnnotationAdvisor dynamicDatasourceAnnotationAdvisor(DynamicDataSourceSpelParser dynamicDataSourceSpelParser, DynamicDataSourceSpelResolver dynamicDataSourceSpelResolver) {
+ DynamicDataSourceAnnotationInterceptor interceptor = new DynamicDataSourceAnnotationInterceptor();
+ interceptor.setDynamicDataSourceSpelParser(dynamicDataSourceSpelParser);
+ interceptor.setDynamicDataSourceSpelResolver(dynamicDataSourceSpelResolver);
+ DynamicDataSourceAnnotationAdvisor advisor = new DynamicDataSourceAnnotationAdvisor(interceptor);
+ advisor.setOrder(properties.getOrder());
+ return advisor;
+ }
+
+ @Bean
+ @ConditionalOnMissingBean
+ public DynamicDataSourceSpelParser dynamicDataSourceSpelParser() {
+ return new DefaultDynamicDataSourceSpelParser();
+ }
+
+ @Bean
+ @ConditionalOnMissingBean
+ public DynamicDataSourceSpelResolver dynamicDataSourceSpelResolver() {
+ return new DefaultDynamicDataSourceSpelResolver();
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/baomidou/dynamic/datasource/spring/boot/autoconfigure/DynamicDataSourceProperties.java b/src/main/java/com/baomidou/dynamic/datasource/spring/boot/autoconfigure/DynamicDataSourceProperties.java
new file mode 100644
index 0000000..50b7a2a
--- /dev/null
+++ b/src/main/java/com/baomidou/dynamic/datasource/spring/boot/autoconfigure/DynamicDataSourceProperties.java
@@ -0,0 +1,75 @@
+/**
+ * Copyright © 2018 organization baomidou
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+package com.baomidou.dynamic.datasource.spring.boot.autoconfigure;
+
+import com.baomidou.dynamic.datasource.spring.boot.autoconfigure.druid.DruidConfig;
+import com.baomidou.dynamic.datasource.strategy.DynamicDataSourceStrategy;
+import com.baomidou.dynamic.datasource.strategy.LoadBalanceDynamicDataSourceStrategy;
+import com.zaxxer.hikari.HikariConfig;
+import lombok.Getter;
+import lombok.Setter;
+import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.boot.context.properties.NestedConfigurationProperty;
+import org.springframework.core.Ordered;
+
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+/**
+ * DynamicDataSourceProperties
+ *
+ * @author TaoYu Kanyuxia
+ * @see DataSourceProperties
+ * @since 1.0.0
+ */
+@Getter
+@Setter
+@ConfigurationProperties(prefix = "spring.datasource.dynamic")
+public class DynamicDataSourceProperties {
+
+ /**
+ * 必须设置默认的库,默认master
+ */
+ private String primary = "master";
+ /**
+ * 每一个数据源
+ */
+ private Map datasource = new LinkedHashMap<>();
+ /**
+ * 多数据源选择算法clazz,默认负载均衡算法
+ */
+ private Class extends DynamicDataSourceStrategy> strategy = LoadBalanceDynamicDataSourceStrategy.class;
+ /**
+ * aop切面顺序,默认优先级最高
+ */
+ private Integer order = Ordered.HIGHEST_PRECEDENCE;
+ /**
+ * 是否使用p6spy输出,默认不输出
+ */
+ private Boolean p6spy = false;
+ /**
+ * Druid全局参数配置
+ */
+ @NestedConfigurationProperty
+ private DruidConfig druid = new DruidConfig();
+ /**
+ * HikariCp全局参数配置
+ */
+ @NestedConfigurationProperty
+ private HikariConfig hikari = new HikariConfig();
+}
diff --git a/src/main/java/com/baomidou/dynamic/datasource/spring/boot/autoconfigure/druid/DruidConfig.java b/src/main/java/com/baomidou/dynamic/datasource/spring/boot/autoconfigure/druid/DruidConfig.java
new file mode 100644
index 0000000..c12c22a
--- /dev/null
+++ b/src/main/java/com/baomidou/dynamic/datasource/spring/boot/autoconfigure/druid/DruidConfig.java
@@ -0,0 +1,244 @@
+/**
+ * Copyright © 2018 organization baomidou
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+package com.baomidou.dynamic.datasource.spring.boot.autoconfigure.druid;
+
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import lombok.experimental.Accessors;
+import lombok.extern.slf4j.Slf4j;
+
+import java.util.Properties;
+
+import static com.alibaba.druid.pool.DruidAbstractDataSource.*;
+
+/**
+ * Druid常用参数
+ *
+ * @author TaoYu
+ * @since 1.2.0
+ */
+@Data
+@Accessors(chain = true)
+@NoArgsConstructor
+@Slf4j
+public class DruidConfig {
+
+ private Integer initialSize;
+ private Integer maxActive;
+ private Integer minIdle;
+ private Long maxWait;
+ private Long timeBetweenEvictionRunsMillis;
+ private Long timeBetweenLogStatsMillis;
+ private Integer statSqlMaxSize;
+ private Long minEvictableIdleTimeMillis;
+ private Long maxEvictableIdleTimeMillis;
+ private Boolean testWhileIdle;
+ private Boolean testOnBorrow;
+ private Boolean testOnReturn;
+ private String validationQuery;
+ private Integer validationQueryTimeout;
+ private Boolean useGlobalDataSourceStat;
+ private Boolean asyncInit;
+ private String filters;
+ private Boolean clearFiltersEnable;
+ private Boolean resetStatEnable;
+ private Integer notFullTimeoutRetryCount;
+ private Long maxWaitThreadCount;
+ private Boolean failFast;
+ private Integer phyTimeoutMillis;
+ private Boolean keepAlive;
+ private Boolean poolPreparedStatements;
+ private Boolean initVariants;
+ private Boolean initGlobalVariants;
+ private Boolean useUnfairLock;
+ private Boolean killWhenSocketReadTimeout;
+ private String connectionProperties;
+ private Integer maxPoolPreparedStatementPerConnectionSize;
+ private String initConnectionSqls;
+ private Boolean sharePreparedStatements;
+ private Integer connectionErrorRetryAttempts;
+ private Boolean breakAfterAcquireFailure;
+
+ private String publicKey;
+
+ public Properties toProperties(DruidConfig config) {
+ Properties properties = new Properties();
+ Integer initialSize = this.initialSize == null ? config.getInitialSize() : this.initialSize;
+ if (initialSize != null && !initialSize.equals(DEFAULT_INITIAL_SIZE)) {
+ properties.setProperty("druid.initialSize", String.valueOf(initialSize));
+ }
+
+ Integer maxActive = this.maxActive == null ? config.getMaxActive() : this.maxActive;
+ if (maxActive != null && !maxActive.equals(DEFAULT_MAX_WAIT)) {
+ properties.setProperty("druid.maxActive", String.valueOf(maxActive));
+ }
+
+ Integer minIdle = this.minIdle == null ? config.getMinIdle() : this.minIdle;
+ if (minIdle != null && !minIdle.equals(DEFAULT_MIN_IDLE)) {
+ properties.setProperty("druid.minIdle", String.valueOf(minIdle));
+ }
+
+ Long maxWait = this.maxWait == null ? config.getMaxWait() : this.maxWait;
+ if (maxWait != null && !maxWait.equals(DEFAULT_MAX_WAIT)) {
+ properties.setProperty("druid.maxWait", String.valueOf(maxWait));
+ }
+
+ Long timeBetweenEvictionRunsMillis = this.timeBetweenEvictionRunsMillis == null ? config.getTimeBetweenEvictionRunsMillis() : this.timeBetweenEvictionRunsMillis;
+ if (timeBetweenEvictionRunsMillis != null && !timeBetweenEvictionRunsMillis.equals(DEFAULT_TIME_BETWEEN_EVICTION_RUNS_MILLIS)) {
+ properties.setProperty("druid.timeBetweenEvictionRunsMillis", String.valueOf(timeBetweenEvictionRunsMillis));
+ }
+
+ Long timeBetweenLogStatsMillis = this.timeBetweenLogStatsMillis == null ? config.getTimeBetweenLogStatsMillis() : this.timeBetweenLogStatsMillis;
+ if (timeBetweenLogStatsMillis != null && timeBetweenLogStatsMillis > 0) {
+ properties.setProperty("druid.timeBetweenLogStatsMillis", String.valueOf(timeBetweenLogStatsMillis));
+ }
+
+ Integer statSqlMaxSize = this.statSqlMaxSize == null ? config.getStatSqlMaxSize() : this.statSqlMaxSize;
+ if (statSqlMaxSize != null) {
+ properties.setProperty("druid.stat.sql.MaxSize", String.valueOf(statSqlMaxSize));
+ }
+
+ Long minEvictableIdleTimeMillis = this.minEvictableIdleTimeMillis == null ? config.getMinEvictableIdleTimeMillis() : this.minEvictableIdleTimeMillis;
+ if (minEvictableIdleTimeMillis != null && !minEvictableIdleTimeMillis.equals(DEFAULT_MIN_EVICTABLE_IDLE_TIME_MILLIS)) {
+ properties.setProperty("druid.minEvictableIdleTimeMillis", String.valueOf(minEvictableIdleTimeMillis));
+ }
+
+ Long maxEvictableIdleTimeMillis = this.maxEvictableIdleTimeMillis == null ? config.getMaxEvictableIdleTimeMillis() : this.maxEvictableIdleTimeMillis;
+ if (maxEvictableIdleTimeMillis != null && !maxEvictableIdleTimeMillis.equals(DEFAULT_MAX_EVICTABLE_IDLE_TIME_MILLIS)) {
+ properties.setProperty("druid.maxEvictableIdleTimeMillis", String.valueOf(maxEvictableIdleTimeMillis));
+ }
+
+ Boolean testWhileIdle = this.testWhileIdle == null ? config.getTestWhileIdle() : this.testWhileIdle;
+ if (testWhileIdle != null && !testWhileIdle.equals(DEFAULT_WHILE_IDLE)) {
+ properties.setProperty("druid.testWhileIdle", "false");
+ }
+
+ Boolean testOnBorrow = this.testOnBorrow == null ? config.getTestOnBorrow() : this.testOnBorrow;
+ if (testOnBorrow != null && !testOnBorrow.equals(DEFAULT_TEST_ON_BORROW)) {
+ properties.setProperty("druid.testOnBorrow", "true");
+ }
+
+ String validationQuery = this.validationQuery == null ? config.getValidationQuery() : this.validationQuery;
+ if (validationQuery != null && validationQuery.length() > 0) {
+ properties.setProperty("druid.validationQuery", validationQuery);
+ }
+
+ Boolean useGlobalDataSourceStat = this.useGlobalDataSourceStat == null ? config.getUseGlobalDataSourceStat() : this.useGlobalDataSourceStat;
+ if (useGlobalDataSourceStat != null && useGlobalDataSourceStat.equals(Boolean.TRUE)) {
+ properties.setProperty("druid.useGlobalDataSourceStat", "true");
+ }
+
+ Boolean asyncInit = this.asyncInit == null ? config.getAsyncInit() : this.asyncInit;
+ if (asyncInit != null && asyncInit.equals(Boolean.TRUE)) {
+ properties.setProperty("druid.asyncInit", "true");
+ }
+
+ //filters单独处理,默认了stat,wall
+ String filters = this.filters == null ? config.getFilters() : this.filters;
+ if (filters == null) {
+ filters = "stat,wall";
+ }
+ if (publicKey != null && publicKey.length() > 0 && !filters.contains("config")) {
+ filters += ",config";
+ }
+ properties.setProperty("druid.filters", filters);
+
+ Boolean clearFiltersEnable = this.clearFiltersEnable == null ? config.getClearFiltersEnable() : this.clearFiltersEnable;
+ if (clearFiltersEnable != null && clearFiltersEnable.equals(Boolean.FALSE)) {
+ properties.setProperty("druid.clearFiltersEnable", "false");
+ }
+
+ Boolean resetStatEnable = this.resetStatEnable == null ? config.getResetStatEnable() : this.resetStatEnable;
+ if (resetStatEnable != null && resetStatEnable.equals(Boolean.FALSE)) {
+ properties.setProperty("druid.resetStatEnable", "false");
+ }
+
+ Integer notFullTimeoutRetryCount = this.notFullTimeoutRetryCount == null ? config.getNotFullTimeoutRetryCount() : this.notFullTimeoutRetryCount;
+ if (notFullTimeoutRetryCount != null && !notFullTimeoutRetryCount.equals(0)) {
+ properties.setProperty("druid.notFullTimeoutRetryCount", String.valueOf(notFullTimeoutRetryCount));
+ }
+
+ Long maxWaitThreadCount = this.maxWaitThreadCount == null ? config.getMaxWaitThreadCount() : this.maxWaitThreadCount;
+ if (maxWaitThreadCount != null && !maxWaitThreadCount.equals(DEFAULT_MAX_WAIT)) {
+ properties.setProperty("druid.maxWaitThreadCount", String.valueOf(maxWaitThreadCount));
+ }
+
+ Boolean failFast = this.failFast == null ? config.getFailFast() : this.failFast;
+ if (failFast != null && failFast.equals(Boolean.TRUE)) {
+ properties.setProperty("druid.failFast", "true");
+ }
+
+ Integer phyTimeoutMillis = this.phyTimeoutMillis == null ? config.getPhyTimeoutMillis() : this.phyTimeoutMillis;
+ if (phyTimeoutMillis != null && !phyTimeoutMillis.equals(DEFAULT_PHY_TIMEOUT_MILLIS)) {
+ properties.setProperty("druid.phyTimeoutMillis", String.valueOf(phyTimeoutMillis));
+ }
+
+ Boolean keepAlive = this.keepAlive == null ? config.getKeepAlive() : this.keepAlive;
+ if (keepAlive != null && keepAlive.equals(Boolean.TRUE)) {
+ properties.setProperty("druid.keepAlive", "true");
+ }
+
+ Boolean poolPreparedStatements = this.poolPreparedStatements == null ? config.getPoolPreparedStatements() : this.poolPreparedStatements;
+ if (poolPreparedStatements != null && poolPreparedStatements.equals(Boolean.TRUE)) {
+ properties.setProperty("druid.poolPreparedStatements", "true");
+ }
+
+ Boolean initVariants = this.initVariants == null ? config.getInitVariants() : this.initVariants;
+ if (initVariants != null && initVariants.equals(Boolean.TRUE)) {
+ properties.setProperty("druid.initVariants", "true");
+ }
+
+ Boolean initGlobalVariants = this.initGlobalVariants == null ? config.getInitGlobalVariants() : this.initGlobalVariants;
+ if (initGlobalVariants != null && initGlobalVariants.equals(Boolean.TRUE)) {
+ properties.setProperty("druid.initGlobalVariants", "true");
+ }
+
+ Boolean useUnfairLock = this.useUnfairLock == null ? config.getUseUnfairLock() : this.useUnfairLock;
+ if (useUnfairLock != null) {
+ properties.setProperty("druid.useUnfairLock", String.valueOf(useUnfairLock));
+ }
+
+ Boolean killWhenSocketReadTimeout = this.killWhenSocketReadTimeout == null ? config.getKillWhenSocketReadTimeout() : this.killWhenSocketReadTimeout;
+ if (killWhenSocketReadTimeout != null && killWhenSocketReadTimeout.equals(Boolean.TRUE)) {
+ properties.setProperty("druid.killWhenSocketReadTimeout", "true");
+ }
+
+ String connectProperties = this.connectionProperties == null ? config.getConnectionProperties() : this.connectionProperties;
+
+ if (this.publicKey != null && this.publicKey.length() > 0) {
+ if (connectProperties == null) {
+ connectProperties = "";
+ }
+ log.info("动态数据源-检测到您配置了druid加密,加密所需连接参数已为您自动配置");
+ connectProperties += "config.decrypt=true;config.decrypt.key=" + this.publicKey;
+ }
+ if (connectProperties != null && connectProperties.length() > 0) {
+ properties.setProperty("druid.connectProperties", connectProperties);
+ }
+
+ Integer maxPoolPreparedStatementPerConnectionSize = this.maxPoolPreparedStatementPerConnectionSize == null ? config.getMaxPoolPreparedStatementPerConnectionSize() : this.maxPoolPreparedStatementPerConnectionSize;
+ if (maxPoolPreparedStatementPerConnectionSize != null && !maxPoolPreparedStatementPerConnectionSize.equals(10)) {
+ properties.setProperty("druid.maxPoolPreparedStatementPerConnectionSize", String.valueOf(maxPoolPreparedStatementPerConnectionSize));
+ }
+
+ String initConnectionSqls = this.initConnectionSqls == null ? config.getInitConnectionSqls() : this.initConnectionSqls;
+ if (initConnectionSqls != null && initConnectionSqls.length() > 0) {
+ properties.setProperty("druid.initConnectionSqls", initConnectionSqls);
+ }
+ return properties;
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/baomidou/dynamic/datasource/spring/boot/autoconfigure/druid/DruidDynamicDataSourceConfiguration.java b/src/main/java/com/baomidou/dynamic/datasource/spring/boot/autoconfigure/druid/DruidDynamicDataSourceConfiguration.java
new file mode 100644
index 0000000..b783e47
--- /dev/null
+++ b/src/main/java/com/baomidou/dynamic/datasource/spring/boot/autoconfigure/druid/DruidDynamicDataSourceConfiguration.java
@@ -0,0 +1,46 @@
+/**
+ * Copyright © 2018 organization baomidou
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+package com.baomidou.dynamic.datasource.spring.boot.autoconfigure.druid;
+
+import com.alibaba.druid.pool.DruidDataSource;
+import com.alibaba.druid.spring.boot.autoconfigure.properties.DruidStatProperties;
+import com.alibaba.druid.spring.boot.autoconfigure.stat.DruidFilterConfiguration;
+import com.alibaba.druid.spring.boot.autoconfigure.stat.DruidSpringAopConfiguration;
+import com.alibaba.druid.spring.boot.autoconfigure.stat.DruidStatViewServletConfiguration;
+import com.alibaba.druid.spring.boot.autoconfigure.stat.DruidWebStatFilterConfiguration;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
+import org.springframework.boot.context.properties.EnableConfigurationProperties;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.Import;
+
+/**
+ * 从原生DruidDataSourceAutoConfigure复制
+ *
+ * @author TaoYu
+ * @since 1.1.0
+ */
+@Configuration
+@ConditionalOnClass(DruidDataSource.class)
+@EnableConfigurationProperties({DruidStatProperties.class})
+@Import({
+ DruidSpringAopConfiguration.class,
+ DruidStatViewServletConfiguration.class,
+ DruidWebStatFilterConfiguration.class,
+ DruidFilterConfiguration.class})
+public class DruidDynamicDataSourceConfiguration {
+
+}
diff --git a/src/main/java/com/baomidou/dynamic/datasource/strategy/DynamicDataSourceStrategy.java b/src/main/java/com/baomidou/dynamic/datasource/strategy/DynamicDataSourceStrategy.java
new file mode 100644
index 0000000..311d1c4
--- /dev/null
+++ b/src/main/java/com/baomidou/dynamic/datasource/strategy/DynamicDataSourceStrategy.java
@@ -0,0 +1,40 @@
+/**
+ * Copyright © 2018 organization baomidou
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+package com.baomidou.dynamic.datasource.strategy;
+
+import javax.sql.DataSource;
+import java.util.List;
+
+/**
+ * 多数据源选择策略接口
+ * 一般默认为负载均衡策略,默认提供了一个随机策略
+ *
+ * @author TaoYu Kanyuxia
+ * @see RandomDynamicDataSourceStrategy
+ * @see LoadBalanceDynamicDataSourceStrategy
+ * @since 1.0.0
+ */
+public interface DynamicDataSourceStrategy {
+
+ /**
+ * 决定当前数据源
+ *
+ * @param dataSources 数据源选择库
+ * @return dataSource 所选择的数据源
+ */
+ DataSource determineDataSource(List dataSources);
+}
diff --git a/src/main/java/com/baomidou/dynamic/datasource/strategy/LoadBalanceDynamicDataSourceStrategy.java b/src/main/java/com/baomidou/dynamic/datasource/strategy/LoadBalanceDynamicDataSourceStrategy.java
new file mode 100644
index 0000000..310b4dd
--- /dev/null
+++ b/src/main/java/com/baomidou/dynamic/datasource/strategy/LoadBalanceDynamicDataSourceStrategy.java
@@ -0,0 +1,40 @@
+/**
+ * Copyright © 2018 organization baomidou
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+package com.baomidou.dynamic.datasource.strategy;
+
+import javax.sql.DataSource;
+import java.util.List;
+import java.util.concurrent.atomic.AtomicInteger;
+
+/**
+ * 负载均衡策略
+ *
+ * @author TaoYu Kanyuxia
+ * @since 1.0.0
+ */
+public class LoadBalanceDynamicDataSourceStrategy implements DynamicDataSourceStrategy {
+
+ /**
+ * 负载均衡计数器
+ */
+ private AtomicInteger index = new AtomicInteger(0);
+
+ @Override
+ public DataSource determineDataSource(List dataSources) {
+ return dataSources.get(Math.abs(index.getAndAdd(1)) % dataSources.size());
+ }
+}
diff --git a/src/main/java/com/baomidou/dynamic/datasource/strategy/RandomDynamicDataSourceStrategy.java b/src/main/java/com/baomidou/dynamic/datasource/strategy/RandomDynamicDataSourceStrategy.java
new file mode 100644
index 0000000..b44833c
--- /dev/null
+++ b/src/main/java/com/baomidou/dynamic/datasource/strategy/RandomDynamicDataSourceStrategy.java
@@ -0,0 +1,35 @@
+/**
+ * Copyright © 2018 organization baomidou
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+package com.baomidou.dynamic.datasource.strategy;
+
+import javax.sql.DataSource;
+import java.util.List;
+import java.util.concurrent.ThreadLocalRandom;
+
+/**
+ * 随机策略
+ *
+ * @author TaoYu Kanyuxia
+ * @since 1.0.0
+ */
+public class RandomDynamicDataSourceStrategy implements DynamicDataSourceStrategy {
+
+ @Override
+ public DataSource determineDataSource(List dataSources) {
+ return dataSources.get(ThreadLocalRandom.current().nextInt(dataSources.size()));
+ }
+}
diff --git a/src/main/java/com/baomidou/dynamic/datasource/toolkit/DynamicDataSourceContextHolder.java b/src/main/java/com/baomidou/dynamic/datasource/toolkit/DynamicDataSourceContextHolder.java
new file mode 100644
index 0000000..4bdb1a4
--- /dev/null
+++ b/src/main/java/com/baomidou/dynamic/datasource/toolkit/DynamicDataSourceContextHolder.java
@@ -0,0 +1,82 @@
+/**
+ * Copyright © 2018 organization baomidou
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+package com.baomidou.dynamic.datasource.toolkit;
+
+import java.util.concurrent.LinkedBlockingDeque;
+
+/**
+ * 核心基于ThreadLocal的切换数据源工具类
+ *
+ * @author TaoYu Kanyuxia
+ * @since 1.0.0
+ */
+public final class DynamicDataSourceContextHolder {
+
+ /**
+ * 为什么要用链表存储(准确的是栈)
+ *
+ * 为了支持嵌套切换,如ABC三个service都是不同的数据源
+ * 其中A的某个业务要调B的方法,B的方法需要调用C的方法。一级一级调用切换,形成了链。
+ * 传统的只设置当前线程的方式不能满足此业务需求,必须模拟栈,后进先出。
+ *
+ */
+ @SuppressWarnings("unchecked")
+ private static final ThreadLocal> LOOKUP_KEY_HOLDER = new ThreadLocal() {
+ @Override
+ protected Object initialValue() {
+ return new LinkedBlockingDeque();
+ }
+ };
+
+ private DynamicDataSourceContextHolder() {
+ }
+
+ /**
+ * 获得当前线程数据源
+ *
+ * @return 数据源名称
+ */
+ public static String getDataSourceLookupKey() {
+ LinkedBlockingDeque deque = LOOKUP_KEY_HOLDER.get();
+ return deque.isEmpty() ? null : deque.getFirst();
+ }
+
+ /**
+ * 设置当前线程数据源
+ *
+ * @param dataSourceLookupKey 数据源名称
+ */
+ public static void setDataSourceLookupKey(String dataSourceLookupKey) {
+ LOOKUP_KEY_HOLDER.get().addFirst(dataSourceLookupKey);
+ }
+
+ /**
+ * 清空当前线程数据源
+ *
+ * 如果当前线程是连续切换数据源
+ * 只会移除掉当前线程的数据源名称
+ *
+ */
+ public static void clearDataSourceLookupKey() {
+ LinkedBlockingDeque deque = LOOKUP_KEY_HOLDER.get();
+ if (deque.isEmpty()) {
+ LOOKUP_KEY_HOLDER.remove();
+ } else {
+ deque.pollFirst();
+ }
+ }
+}
diff --git a/src/main/resources/META-INF/spring.factories b/src/main/resources/META-INF/spring.factories
new file mode 100644
index 0000000..6d4b5af
--- /dev/null
+++ b/src/main/resources/META-INF/spring.factories
@@ -0,0 +1,2 @@
+org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
+com.baomidou.dynamic.datasource.spring.boot.autoconfigure.DynamicDataSourceAutoConfiguration
\ No newline at end of file
diff --git a/target/classes/META-INF/spring-configuration-metadata.json b/target/classes/META-INF/spring-configuration-metadata.json
new file mode 100644
index 0000000..2e39106
--- /dev/null
+++ b/target/classes/META-INF/spring-configuration-metadata.json
@@ -0,0 +1,410 @@
+{
+ "hints": [],
+ "groups": [
+ {
+ "sourceType": "com.baomidou.dynamic.datasource.spring.boot.autoconfigure.DynamicDataSourceProperties",
+ "name": "spring.datasource.dynamic",
+ "type": "com.baomidou.dynamic.datasource.spring.boot.autoconfigure.DynamicDataSourceProperties"
+ },
+ {
+ "sourceType": "com.baomidou.dynamic.datasource.spring.boot.autoconfigure.DynamicDataSourceProperties",
+ "name": "spring.datasource.dynamic.druid",
+ "type": "com.baomidou.dynamic.datasource.spring.boot.autoconfigure.druid.DruidConfig"
+ },
+ {
+ "sourceType": "com.baomidou.dynamic.datasource.spring.boot.autoconfigure.DynamicDataSourceProperties",
+ "name": "spring.datasource.dynamic.hikari",
+ "type": "com.zaxxer.hikari.HikariConfig"
+ }
+ ],
+ "properties": [
+ {
+ "sourceType": "com.baomidou.dynamic.datasource.spring.boot.autoconfigure.DynamicDataSourceProperties",
+ "name": "spring.datasource.dynamic.datasource",
+ "description": "每一个数据源",
+ "type": "java.util.Map"
+ },
+ {
+ "sourceType": "com.baomidou.dynamic.datasource.spring.boot.autoconfigure.druid.DruidConfig",
+ "name": "spring.datasource.dynamic.druid.async-init",
+ "type": "java.lang.Boolean"
+ },
+ {
+ "sourceType": "com.baomidou.dynamic.datasource.spring.boot.autoconfigure.druid.DruidConfig",
+ "name": "spring.datasource.dynamic.druid.break-after-acquire-failure",
+ "type": "java.lang.Boolean"
+ },
+ {
+ "sourceType": "com.baomidou.dynamic.datasource.spring.boot.autoconfigure.druid.DruidConfig",
+ "name": "spring.datasource.dynamic.druid.clear-filters-enable",
+ "type": "java.lang.Boolean"
+ },
+ {
+ "sourceType": "com.baomidou.dynamic.datasource.spring.boot.autoconfigure.druid.DruidConfig",
+ "name": "spring.datasource.dynamic.druid.connection-error-retry-attempts",
+ "type": "java.lang.Integer"
+ },
+ {
+ "sourceType": "com.baomidou.dynamic.datasource.spring.boot.autoconfigure.druid.DruidConfig",
+ "name": "spring.datasource.dynamic.druid.connection-properties",
+ "type": "java.lang.String"
+ },
+ {
+ "sourceType": "com.baomidou.dynamic.datasource.spring.boot.autoconfigure.druid.DruidConfig",
+ "name": "spring.datasource.dynamic.druid.fail-fast",
+ "type": "java.lang.Boolean"
+ },
+ {
+ "sourceType": "com.baomidou.dynamic.datasource.spring.boot.autoconfigure.druid.DruidConfig",
+ "name": "spring.datasource.dynamic.druid.filters",
+ "type": "java.lang.String"
+ },
+ {
+ "sourceType": "com.baomidou.dynamic.datasource.spring.boot.autoconfigure.druid.DruidConfig",
+ "name": "spring.datasource.dynamic.druid.init-connection-sqls",
+ "type": "java.lang.String"
+ },
+ {
+ "sourceType": "com.baomidou.dynamic.datasource.spring.boot.autoconfigure.druid.DruidConfig",
+ "name": "spring.datasource.dynamic.druid.init-global-variants",
+ "type": "java.lang.Boolean"
+ },
+ {
+ "sourceType": "com.baomidou.dynamic.datasource.spring.boot.autoconfigure.druid.DruidConfig",
+ "name": "spring.datasource.dynamic.druid.init-variants",
+ "type": "java.lang.Boolean"
+ },
+ {
+ "sourceType": "com.baomidou.dynamic.datasource.spring.boot.autoconfigure.druid.DruidConfig",
+ "name": "spring.datasource.dynamic.druid.initial-size",
+ "type": "java.lang.Integer"
+ },
+ {
+ "sourceType": "com.baomidou.dynamic.datasource.spring.boot.autoconfigure.druid.DruidConfig",
+ "name": "spring.datasource.dynamic.druid.keep-alive",
+ "type": "java.lang.Boolean"
+ },
+ {
+ "sourceType": "com.baomidou.dynamic.datasource.spring.boot.autoconfigure.druid.DruidConfig",
+ "name": "spring.datasource.dynamic.druid.kill-when-socket-read-timeout",
+ "type": "java.lang.Boolean"
+ },
+ {
+ "sourceType": "com.baomidou.dynamic.datasource.spring.boot.autoconfigure.druid.DruidConfig",
+ "name": "spring.datasource.dynamic.druid.max-active",
+ "type": "java.lang.Integer"
+ },
+ {
+ "sourceType": "com.baomidou.dynamic.datasource.spring.boot.autoconfigure.druid.DruidConfig",
+ "name": "spring.datasource.dynamic.druid.max-evictable-idle-time-millis",
+ "type": "java.lang.Long"
+ },
+ {
+ "sourceType": "com.baomidou.dynamic.datasource.spring.boot.autoconfigure.druid.DruidConfig",
+ "name": "spring.datasource.dynamic.druid.max-pool-prepared-statement-per-connection-size",
+ "type": "java.lang.Integer"
+ },
+ {
+ "sourceType": "com.baomidou.dynamic.datasource.spring.boot.autoconfigure.druid.DruidConfig",
+ "name": "spring.datasource.dynamic.druid.max-wait",
+ "type": "java.lang.Long"
+ },
+ {
+ "sourceType": "com.baomidou.dynamic.datasource.spring.boot.autoconfigure.druid.DruidConfig",
+ "name": "spring.datasource.dynamic.druid.max-wait-thread-count",
+ "type": "java.lang.Long"
+ },
+ {
+ "sourceType": "com.baomidou.dynamic.datasource.spring.boot.autoconfigure.druid.DruidConfig",
+ "name": "spring.datasource.dynamic.druid.min-evictable-idle-time-millis",
+ "type": "java.lang.Long"
+ },
+ {
+ "sourceType": "com.baomidou.dynamic.datasource.spring.boot.autoconfigure.druid.DruidConfig",
+ "name": "spring.datasource.dynamic.druid.min-idle",
+ "type": "java.lang.Integer"
+ },
+ {
+ "sourceType": "com.baomidou.dynamic.datasource.spring.boot.autoconfigure.druid.DruidConfig",
+ "name": "spring.datasource.dynamic.druid.not-full-timeout-retry-count",
+ "type": "java.lang.Integer"
+ },
+ {
+ "sourceType": "com.baomidou.dynamic.datasource.spring.boot.autoconfigure.druid.DruidConfig",
+ "name": "spring.datasource.dynamic.druid.phy-timeout-millis",
+ "type": "java.lang.Integer"
+ },
+ {
+ "sourceType": "com.baomidou.dynamic.datasource.spring.boot.autoconfigure.druid.DruidConfig",
+ "name": "spring.datasource.dynamic.druid.pool-prepared-statements",
+ "type": "java.lang.Boolean"
+ },
+ {
+ "sourceType": "com.baomidou.dynamic.datasource.spring.boot.autoconfigure.druid.DruidConfig",
+ "name": "spring.datasource.dynamic.druid.public-key",
+ "type": "java.lang.String"
+ },
+ {
+ "sourceType": "com.baomidou.dynamic.datasource.spring.boot.autoconfigure.druid.DruidConfig",
+ "name": "spring.datasource.dynamic.druid.reset-stat-enable",
+ "type": "java.lang.Boolean"
+ },
+ {
+ "sourceType": "com.baomidou.dynamic.datasource.spring.boot.autoconfigure.druid.DruidConfig",
+ "name": "spring.datasource.dynamic.druid.share-prepared-statements",
+ "type": "java.lang.Boolean"
+ },
+ {
+ "sourceType": "com.baomidou.dynamic.datasource.spring.boot.autoconfigure.druid.DruidConfig",
+ "name": "spring.datasource.dynamic.druid.stat-sql-max-size",
+ "type": "java.lang.Integer"
+ },
+ {
+ "sourceType": "com.baomidou.dynamic.datasource.spring.boot.autoconfigure.druid.DruidConfig",
+ "name": "spring.datasource.dynamic.druid.test-on-borrow",
+ "type": "java.lang.Boolean"
+ },
+ {
+ "sourceType": "com.baomidou.dynamic.datasource.spring.boot.autoconfigure.druid.DruidConfig",
+ "name": "spring.datasource.dynamic.druid.test-on-return",
+ "type": "java.lang.Boolean"
+ },
+ {
+ "sourceType": "com.baomidou.dynamic.datasource.spring.boot.autoconfigure.druid.DruidConfig",
+ "name": "spring.datasource.dynamic.druid.test-while-idle",
+ "type": "java.lang.Boolean"
+ },
+ {
+ "sourceType": "com.baomidou.dynamic.datasource.spring.boot.autoconfigure.druid.DruidConfig",
+ "name": "spring.datasource.dynamic.druid.time-between-eviction-runs-millis",
+ "type": "java.lang.Long"
+ },
+ {
+ "sourceType": "com.baomidou.dynamic.datasource.spring.boot.autoconfigure.druid.DruidConfig",
+ "name": "spring.datasource.dynamic.druid.time-between-log-stats-millis",
+ "type": "java.lang.Long"
+ },
+ {
+ "sourceType": "com.baomidou.dynamic.datasource.spring.boot.autoconfigure.druid.DruidConfig",
+ "name": "spring.datasource.dynamic.druid.use-global-data-source-stat",
+ "type": "java.lang.Boolean"
+ },
+ {
+ "sourceType": "com.baomidou.dynamic.datasource.spring.boot.autoconfigure.druid.DruidConfig",
+ "name": "spring.datasource.dynamic.druid.use-unfair-lock",
+ "type": "java.lang.Boolean"
+ },
+ {
+ "sourceType": "com.baomidou.dynamic.datasource.spring.boot.autoconfigure.druid.DruidConfig",
+ "name": "spring.datasource.dynamic.druid.validation-query",
+ "type": "java.lang.String"
+ },
+ {
+ "sourceType": "com.baomidou.dynamic.datasource.spring.boot.autoconfigure.druid.DruidConfig",
+ "name": "spring.datasource.dynamic.druid.validation-query-timeout",
+ "type": "java.lang.Integer"
+ },
+ {
+ "sourceType": "com.zaxxer.hikari.HikariConfig",
+ "name": "spring.datasource.dynamic.hikari.allow-pool-suspension",
+ "type": "java.lang.Boolean"
+ },
+ {
+ "sourceType": "com.zaxxer.hikari.HikariConfig",
+ "name": "spring.datasource.dynamic.hikari.auto-commit",
+ "type": "java.lang.Boolean"
+ },
+ {
+ "sourceType": "com.zaxxer.hikari.HikariConfig",
+ "name": "spring.datasource.dynamic.hikari.catalog",
+ "type": "java.lang.String"
+ },
+ {
+ "sourceType": "com.zaxxer.hikari.HikariConfig",
+ "name": "spring.datasource.dynamic.hikari.connection-init-sql",
+ "type": "java.lang.String"
+ },
+ {
+ "sourceType": "com.zaxxer.hikari.HikariConfig",
+ "name": "spring.datasource.dynamic.hikari.connection-test-query",
+ "type": "java.lang.String"
+ },
+ {
+ "sourceType": "com.zaxxer.hikari.HikariConfig",
+ "name": "spring.datasource.dynamic.hikari.connection-timeout",
+ "type": "java.lang.Long"
+ },
+ {
+ "sourceType": "com.zaxxer.hikari.HikariConfig",
+ "name": "spring.datasource.dynamic.hikari.data-source-class-name",
+ "type": "java.lang.String"
+ },
+ {
+ "sourceType": "com.zaxxer.hikari.HikariConfig",
+ "name": "spring.datasource.dynamic.hikari.data-source-j-n-d-i",
+ "type": "java.lang.String"
+ },
+ {
+ "sourceType": "com.zaxxer.hikari.HikariConfig",
+ "name": "spring.datasource.dynamic.hikari.data-source-properties",
+ "type": "java.util.Properties"
+ },
+ {
+ "sourceType": "com.zaxxer.hikari.HikariConfig",
+ "name": "spring.datasource.dynamic.hikari.driver-class-name",
+ "type": "java.lang.String"
+ },
+ {
+ "sourceType": "com.zaxxer.hikari.HikariConfig",
+ "name": "spring.datasource.dynamic.hikari.health-check-properties",
+ "type": "java.util.Properties"
+ },
+ {
+ "sourceType": "com.zaxxer.hikari.HikariConfig",
+ "name": "spring.datasource.dynamic.hikari.health-check-registry",
+ "type": "java.lang.Object"
+ },
+ {
+ "sourceType": "com.zaxxer.hikari.HikariConfig",
+ "name": "spring.datasource.dynamic.hikari.idle-timeout",
+ "type": "java.lang.Long"
+ },
+ {
+ "sourceType": "com.zaxxer.hikari.HikariConfig",
+ "deprecated": true,
+ "name": "spring.datasource.dynamic.hikari.initialization-fail-fast",
+ "type": "java.lang.Boolean",
+ "deprecation": {}
+ },
+ {
+ "sourceType": "com.zaxxer.hikari.HikariConfig",
+ "name": "spring.datasource.dynamic.hikari.initialization-fail-timeout",
+ "type": "java.lang.Long"
+ },
+ {
+ "sourceType": "com.zaxxer.hikari.HikariConfig",
+ "name": "spring.datasource.dynamic.hikari.isolate-internal-queries",
+ "type": "java.lang.Boolean"
+ },
+ {
+ "sourceType": "com.zaxxer.hikari.HikariConfig",
+ "name": "spring.datasource.dynamic.hikari.jdbc-url",
+ "type": "java.lang.String"
+ },
+ {
+ "sourceType": "com.zaxxer.hikari.HikariConfig",
+ "deprecated": true,
+ "name": "spring.datasource.dynamic.hikari.jdbc4-connection-test",
+ "type": "java.lang.Boolean",
+ "deprecation": {}
+ },
+ {
+ "sourceType": "com.zaxxer.hikari.HikariConfig",
+ "name": "spring.datasource.dynamic.hikari.leak-detection-threshold",
+ "type": "java.lang.Long"
+ },
+ {
+ "sourceType": "com.zaxxer.hikari.HikariConfig",
+ "name": "spring.datasource.dynamic.hikari.max-lifetime",
+ "type": "java.lang.Long"
+ },
+ {
+ "sourceType": "com.zaxxer.hikari.HikariConfig",
+ "name": "spring.datasource.dynamic.hikari.maximum-pool-size",
+ "type": "java.lang.Integer"
+ },
+ {
+ "sourceType": "com.zaxxer.hikari.HikariConfig",
+ "name": "spring.datasource.dynamic.hikari.metric-registry",
+ "type": "java.lang.Object"
+ },
+ {
+ "sourceType": "com.zaxxer.hikari.HikariConfig",
+ "name": "spring.datasource.dynamic.hikari.metrics-tracker-factory",
+ "type": "com.zaxxer.hikari.metrics.MetricsTrackerFactory"
+ },
+ {
+ "sourceType": "com.zaxxer.hikari.HikariConfig",
+ "name": "spring.datasource.dynamic.hikari.minimum-idle",
+ "type": "java.lang.Integer"
+ },
+ {
+ "sourceType": "com.zaxxer.hikari.HikariConfig",
+ "name": "spring.datasource.dynamic.hikari.password",
+ "type": "java.lang.String"
+ },
+ {
+ "sourceType": "com.zaxxer.hikari.HikariConfig",
+ "name": "spring.datasource.dynamic.hikari.pool-name",
+ "type": "java.lang.String"
+ },
+ {
+ "sourceType": "com.zaxxer.hikari.HikariConfig",
+ "name": "spring.datasource.dynamic.hikari.read-only",
+ "type": "java.lang.Boolean"
+ },
+ {
+ "sourceType": "com.zaxxer.hikari.HikariConfig",
+ "name": "spring.datasource.dynamic.hikari.register-mbeans",
+ "type": "java.lang.Boolean"
+ },
+ {
+ "sourceType": "com.zaxxer.hikari.HikariConfig",
+ "name": "spring.datasource.dynamic.hikari.scheduled-executor",
+ "type": "java.util.concurrent.ScheduledExecutorService"
+ },
+ {
+ "sourceType": "com.zaxxer.hikari.HikariConfig",
+ "deprecated": true,
+ "name": "spring.datasource.dynamic.hikari.scheduled-executor-service",
+ "type": "java.util.concurrent.ScheduledThreadPoolExecutor",
+ "deprecation": {}
+ },
+ {
+ "sourceType": "com.zaxxer.hikari.HikariConfig",
+ "name": "spring.datasource.dynamic.hikari.schema",
+ "type": "java.lang.String"
+ },
+ {
+ "sourceType": "com.zaxxer.hikari.HikariConfig",
+ "name": "spring.datasource.dynamic.hikari.transaction-isolation",
+ "type": "java.lang.String"
+ },
+ {
+ "sourceType": "com.zaxxer.hikari.HikariConfig",
+ "name": "spring.datasource.dynamic.hikari.username",
+ "type": "java.lang.String"
+ },
+ {
+ "sourceType": "com.zaxxer.hikari.HikariConfig",
+ "name": "spring.datasource.dynamic.hikari.validation-timeout",
+ "type": "java.lang.Long"
+ },
+ {
+ "sourceType": "com.baomidou.dynamic.datasource.spring.boot.autoconfigure.DynamicDataSourceProperties",
+ "name": "spring.datasource.dynamic.order",
+ "description": "aop切面顺序,默认优先级最高",
+ "type": "java.lang.Integer"
+ },
+ {
+ "sourceType": "com.baomidou.dynamic.datasource.spring.boot.autoconfigure.DynamicDataSourceProperties",
+ "defaultValue": false,
+ "name": "spring.datasource.dynamic.p6spy",
+ "description": "是否使用p6spy输出,默认不输出",
+ "type": "java.lang.Boolean"
+ },
+ {
+ "sourceType": "com.baomidou.dynamic.datasource.spring.boot.autoconfigure.DynamicDataSourceProperties",
+ "defaultValue": "master",
+ "name": "spring.datasource.dynamic.primary",
+ "description": "必须设置默认的库,默认master",
+ "type": "java.lang.String"
+ },
+ {
+ "sourceType": "com.baomidou.dynamic.datasource.spring.boot.autoconfigure.DynamicDataSourceProperties",
+ "name": "spring.datasource.dynamic.strategy",
+ "description": "多数据源选择算法clazz,默认负载均衡算法",
+ "type": "java.lang.Class extends com.baomidou.dynamic.datasource.strategy.DynamicDataSourceStrategy>"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/target/classes/META-INF/spring.factories b/target/classes/META-INF/spring.factories
new file mode 100644
index 0000000..6d4b5af
--- /dev/null
+++ b/target/classes/META-INF/spring.factories
@@ -0,0 +1,2 @@
+org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
+com.baomidou.dynamic.datasource.spring.boot.autoconfigure.DynamicDataSourceAutoConfiguration
\ No newline at end of file
diff --git a/target/classes/com/baomidou/dynamic/datasource/AbstractRoutingDataSource.class b/target/classes/com/baomidou/dynamic/datasource/AbstractRoutingDataSource.class
new file mode 100644
index 0000000000000000000000000000000000000000..689ecdde1ab7e68f826c037fc5519a298f396ab0
GIT binary patch
literal 1539
zcmbVL-BQy)7(LsD7DD)^EsFA^qHRGU@*_}WbWmn=s*bjUGu&;{Py=mJlT_eQ@CCf_
z0&jHi!Uyo79KYQ}8Z6#8o!M-^J$t^hXV3op_5BBcMXamnL0&~SW_vM*yJDDEq2r#I
zEr{WM5{pSJF(fuD+wwOV;@R8|gRU4>S>9VZPSbR^9hYIW16;`MQaM5^wQuBwm`n#+
z)Wrrh$iTKG0ygo_jLZwKHK^#-FofYGRy2%YR1BFU9%xv_nuc*)({Kwj3~T?LMuru~
zt?6D#5lqnx!QUfNW2&2%>wB*W!T+b1wA9WR6vvX%q;vH;wzyU>9yneakwomOJ>P0dn^t`j=?sqA%zL`=3)qy_zwewln*
zA-`5-%XF~uyk!d4F+nXSWmC~wRHmphP4hUI8qsirN-^A|Mao*Jr4ecwms&nzFjSI^
z;RH$L6P^AuZ3`5Mn*$z3l#HJ%8ShXcDz`%=3B*(JM-&dpB`gob+@bZXl$HApxqMCY
literal 0
HcmV?d00001
diff --git a/target/classes/com/baomidou/dynamic/datasource/DynamicDataSourceClassResolver.class b/target/classes/com/baomidou/dynamic/datasource/DynamicDataSourceClassResolver.class
new file mode 100644
index 0000000000000000000000000000000000000000..aada843f1b2f75dcdfd6238f44a09b490de28df2
GIT binary patch
literal 2518
zcmbtWTXz#x6#h;Um?Rxq8p<7^ax+ca1i4wHmP<>eniixL6-7OnoTgJIGjTGh^q08!
z1-#-?YW2b8lMntRmrMN4nY2k;mgwST=A3=s``dfZ{PFiMzXG^`)hrI-dItM(BaNF`
z$64IRCl)@<
z;xjzZ`k!0)LLlh{HGy0?2y3OLw|H^6R1Ru26aS@Bd=Ks*o_sLMt}g)@Gn
z!bRz*X;*n<9WF1+6ZOVd>TWe?m8z@0th-LBDkIqpTA`y#Q!#0ZlzBrjUhk=9;H{XdWE)}d
zc-2q^`nxQ&}cvCv$(ak
z)NID{R84v}97i>qn;j!yEe7G7tP{>N`L5=ik3yF1>dTsWFDGM4Ii3tvwY`f*U!l5v
zKOO9Zx`oB5Y^o@Z(KQ+v^ZquBMB)4^UDPrv*y~OFDvm|ayzv`(_;7Yf2JDTnQH>$Hk
zl_4c*QsC?>ENrHjp?JKk1deUVal=W>rR76A;n~par%pe#h5k||Or3qL^=lFyM4
z+dsq$0w&gOQJc)&RJ_nKS!qUBQmKqWD6-OJVknTWDWNBG}VKC3}6?7
zI7(-`a0>6@JyKIRNhj0f0%y%FgSSW@BBex)0yRdcQ>4}?!#hXK^E_R^C0wM9cWC7j
zCU6-yafLikBSoDoPU8$yoZ#&=Ehls;w4CR=2V=BfV4}mk*?h;85uQd#8O5#_be*tJ
zv>1f2aP9>%NXB>G4Czncp@p|oR65UalDca6j*gOikFgMmCnya6j6DLn3cc&-dx8O7
zppkX#T|@tG$UTLnSxU>p_`>}487TsP?rlHW^|E;4PM)L1(y
zeY(tY#3}S4`4@&PjPXaS#7J2i(4b(&uJV+i;WQ1m!Di@!R3MYvzm5Yx;NbVX@Nb3B
O-G+67&k5cVxb_dmx|Xp3
literal 0
HcmV?d00001
diff --git a/target/classes/com/baomidou/dynamic/datasource/DynamicDataSourceCreator.class b/target/classes/com/baomidou/dynamic/datasource/DynamicDataSourceCreator.class
new file mode 100644
index 0000000000000000000000000000000000000000..020feb1a589dc5fd37e29b8d6d6bdb87b30e7635
GIT binary patch
literal 7568
zcmb_h33ycHxqkm-k~0|&goJef1+-!alZ?nx2%CWr1hPQ_3Mx36oP>d4PCS{xL~Cn%
zYqhnsYSk*WyB2LLjS2&TTNgoFd%ND+YkRwzs9o;bd+qJTdf)H-XSPV>d0L-5&%b=<
z`@iq|zx|(l`>)5J0s?W#DN)p7G=B2EHMHZ_3wi
z`Ek3<&-!uFz$sZi=g0Fhf7_4m$ozsI-yp9MD2P?G}Kp(Y2^6gAaQLAlH^h2pr~qfpsoJ3ZmP
zc=y8H;U>GM$8we_jBnVyWqrfWhWd{B_SP+%*Q^!1-I0Bfa6FRe3AZPmSfYn`W7pV;
zzGNhk+!~3eEQN|o*Ke%fyuRSzlnpHn8nRQ<+S%0Fx^YXJLcM0)E5y2;$X@GO+u0M|
z-PIWlcSVwsK0D<^t#I77_oRBm8xmcy2146iXp;-11ZLE+B1x;+O760|6sF}#=~&%y
zE1C@JZ^R8G2YR!ZWhp0~IW;cTXE_N9kOlNc`uZqMR|YVt%Zcr?oHcR6Tk;Ucbf#kQ
zEY_GVCl%{j+aK#o_9;xrlV!DS$E`?01l|?f6LDf0qzd=Qy13mLiBp-~F`A^gDQfQx
zcSh{Ju`W9m?i!$Iu>zg+xjGAX+IBJ=NhR&5dotx%VV7LELFCZn$g;A>C4Z^QIKyO?
z%jCL9f4}8~wM^lB44x}p9!tcME9og!bGIt^*4SONad}fLVYQ_8c3MtHq%%$kT__rf
zZ{@9I?*SD*Ov=;1+Wx53n~d3_17C7ij0&nd>pdIv)pK@VBi6RXMNL=po=NC=d8}M3
z5oL0rTr|EX+r*K`%d1xse{6d)65Z1r>2=YVY?!o|z?fnf5!%mkk|=anomKwP?UWepocm0E6Rpd+@|vQx>z)UZC0v~<>;(zh$(SZ$8g%c+abn6&m<
z2}vb0$RI(Lkr#^a3D&|;?kyxDRfECM7(+oA;
zP%~IKD3R8y4)oj|vS~?Y2Sc4h6ZBb0S9gWUsqOFa`nP5$Ni37dNi)e$Knmw;R&SG|
zFw0@Bj@xWas+B}r
zD}|{xr?b_P`7Os(v(#)_G*=z79;L8iRAL2Ldlb^*SZ;M=(#?@~vzw{TQ|Fu5gSd&k
zh%-gAoH0w~&~$W|NXS=zrofr7-F>FMndp^$`H1pn;u-;$xH;B@LpJJNxL#q&*(%d$
zN>`Y}qqSZ*)w+&QE8$c-B0fz-!9w0X^pOXLZ+!poU4z5>4-Fr`t!DU(Hx3`Ub?BBs
z_vp~W_YB?lU})$|A9(Gi{jWTE=;dP%58wCY;g8-tbm)L2uaJxN@)HMMJ8{pehwj%%
zhPuF1bJT?jvvPXUCEZRo+NlIfw^yVT&J%I9>(%P=SUWOm3{_>SxvJV!^Hj*hefYGg
zYE-SM!m|Ag_M14wL0u#$^VP*B?!^8ABk4qFs0F54s1})Ov0%Pih9xpARn?3`k#%HM
zV5gJ2!sb*W$;^@`{OqCo4`fw0bjzoPP8`o|?|QYm!R~t;VQ8h6cN!T@;
zsztS$s!eS&)n-9x7laPgWU4I!+bXcj1a`Uj-X!-x<=kRNK^c
zQ(d91G|`U%<~37Yg~O)WA+qiiR}edg&y-?vkuJI7u%WItRYY|vta2OXzrAZ!*m$-m
z8oh6D@0#D=vGvJ$g4bpiz`XjRaPDX~&9sCD%T>y1?Pi&%+OEs0?)N>itaL`V?dTri
zf>BGcK9gy}DtcH(tY}E+8s|4FxD>u@4b=KJv@-!bfC
zVu@~>j&lZfQaRqy4oYDRZz``8t)Gci`SNF9Oh&A4EsOSm+f;9-LV2je?Y1Tq9LT88
zWa*KYgZID^bWOk1x+WEgv-lU>&g-n^lJeA?TNG-KWhIu_XYZlTmgZ~5JDYEa47ohp
zcpws?C|jiH$i26C4=BBB^IlK#^pGZ^;OWFZTY%Y?);nUyy+leX7}$1LjKdWRb#t?N`W77ypxkZpx-G8-LxuL~C+
z3VQY%i7nn;P91aJS-Q~8ur|^Ze*v
znR;UECQB@7*ZGvn4>T_s*D+Ym`Op-U0W$
zz#lm%)&_Q}*}!RI0@3j_Wn_kIj70gErXLAM{o{{9L1NEj;*lqpVK#r^3h@WPa!iws
zjjL&}&<%wiu8S~(`(1ha+1#_+aKEu_b!T?2?#v$5o!OhZGka2ZW)tep>_6R^UAjB7
zQFmwd8Sc!|&bf@d+0=7<4+W^;4~9NMe_nkQs=D|XijJVzn|-ROvg8;_n+{@JbERLe
zd@a@UD$9zWL?DeZM__U{*2mqp;>tj~3mQjIxd$4rK@|j57J?=aG_epgiJ-}apeY1R
z%`yufgugkI#A6y~x=aZcsAk7H&Ls(o7UgYY$1&X#W;#3ztPP=d+S^i1A$7Up0s
z=W0BF2RT2CXYm}N&*Me@AUTV=xPjWZ4(D=g=B^$l)?y-BNTH21wvx&w;W^&|5;l9Ia>XB+WLF6
z_KURKOMIsMjIWgUl5;gV&*Cq!@57Dsk%zd`E7}R~#|MZp87J`%pgca=r6$QxPd$0b_2JfO$HM9DE4!td#G__FYXbW
zm&SR`p_3R-^`CzLW!0SDHAv_MEj6cbe)VA#r!nVVejx0^LGFF-zDD*{gOxLC(wLh@
zbrz#?b|Iu{P%!5Wl9{$a9ma8eEp6A&pQ8tOzv~%G@8P9xpx)n$FmSuKhf^wWlcpVrAlg=xfvIt6Nk1Hi+1S$H7$fy)MR0`0;}^8I3eiE
zLc=b!gwRRBk}UKh7g|c_lwfHVI^TsFga(6#$M_jsJlK2!3$|4*Jc>n6Q%2wxTHfGg
z#HHuZ`oJ9+i%&2q-HFAx3r)BiopjWG+(XQJ=@bWC)m=&4u~hY4{9Z)tUBtPYbQaU?
z@8QbFlPidSHY|?t`xIB=Tp8D;cCrSz(=&jm)(`bMKJ2=oJP5T$v7FqB
zoT12-zSOR72I)r?EPXHT2SkQy8lO4F_Qepw1Wcoy0_%
zk9jAJwfDjwqQ5ut+qx|BI*q)pt|VA;5>taEMaOVy8tV_h3fM@_^F>H>UMRpa}r
z7C$1#AE*WRp<0C>yJqj^zk(Jp)4h*W=*p@-;{aUg$o8wH_#8e@_gJJ%e1W;6m{Pok
zFR~8$D8m!DpBcG?65NU}5mrk6J8+ONgWPMFsgt~wxMw3O-oR!94;lFK8UtTBjVT<*
zbNSWNn9fm_ZwqZ?X&Fmr{;2-1Et8o=Ul>{{|Hz4VYx0ZEK9TWOXc?so>%mZ
z!)Ky%*+@DYMxi5p3xAx$kxbXZ+%M7q6Dp@4!_|-BoD+yJ%sU^$Vj-&BoDp!5=J4P`
LLehj6;pqPZBz{9j
literal 0
HcmV?d00001
diff --git a/target/classes/com/baomidou/dynamic/datasource/DynamicGroupDataSource.class b/target/classes/com/baomidou/dynamic/datasource/DynamicGroupDataSource.class
new file mode 100644
index 0000000000000000000000000000000000000000..8a421046878993a170e9b5bb1b2a062b90d766a7
GIT binary patch
literal 3872
zcmb_eZBr9h6n<{9yII0QA_5wv6)UxnfU$~J6R=hhYYS+_mujhXNw%;W63mN=efj)O2yjzruD}`@K>b6`8a=R2kF^VqCnJCHc
zvWYwLTQ*TKQI%vZg1Z833*}O6dB$FH1iGef*>~-9!7eVOXRBqmxR4b{Ya=_$8TB}3b+yHK>NwK9zyY`7lt_V?43JB4)J#_S1-8DnnIt)39L<_iTqdlRM)
zT@lbum+~|#HsuzbncC94Q@&)+7rbbea(3a0U3TT(Kh&y=E`2<ZeOgSu=>c=vMK~7DfLFGt5fO;7FgGsJ;4%7zIM1tVOf<84)!!D
zFB$$mvTfqw*}*sApj6Z;6$M?~-qsE_C#>s!U`rVJitT*-&i<^Z!H|cVS%GtwN`TzEPN*MMsdW#X-OT$2NsUuxP^-n
zc1Pm_a;oMQ@-pRnn*$E67s0rN@9;gFX1Kp)1U;S~SU=>c2XdVG7_x8;M>xys2B@m@
zW|C}?V8ANOT9|XxOQM{80;jeL$ks0z-=@Ys%C;PshP}M(6luXov*DrMxWIGe$B~cP
z2L83CYsrtj{6(;vzcIr6VZp*66_T~#eOWCKc*mpnAx3%t?{eMGlSN8|`Q4R#3Xyz{
z(6y%sKY^A^J%OGaegflHPwqXgz0kQHg2n=i@z+c@3nYOf802ZcLctJ{+!4>SLU@$4
zBSd{E4EtIqxDWBpO8y2d^$d{^uGaO)A4g!dwd1&l-K%)lu`P_?0FeaJEfLKoh+{+?
z-vaR<-uG=hMy=BRPTFWlJD;H~gkN|Pf{cdY-JbODEXCHx$Em;2{uA`@!+j)6gXq1NJUWQ9GWI&Vum_Xup;Ka=#1d}OY}x?fq$lWiJgjU3zCH9v!kNO
zA{0~)=rVkbJrhjRTG^A;vrML&kCcKD2MA&i=5jncrj2_c?~7*_8E`Y6dW6WxDz@E}
z=dp|?FA|!6W6CtBt9VBDu9yK&$V}+oRbTU6&+i}j;@`Gj!Qa0dKJ4G$A!w6YM#;c
LL3N$zA$;*aWid%+
literal 0
HcmV?d00001
diff --git a/target/classes/com/baomidou/dynamic/datasource/DynamicRoutingDataSource.class b/target/classes/com/baomidou/dynamic/datasource/DynamicRoutingDataSource.class
new file mode 100644
index 0000000000000000000000000000000000000000..92c328882c2feaea9eae79ed03c97fd78894b84a
GIT binary patch
literal 6398
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
literal 0
HcmV?d00001
diff --git a/target/classes/com/baomidou/dynamic/datasource/aop/DynamicDataSourceAnnotationAdvisor.class b/target/classes/com/baomidou/dynamic/datasource/aop/DynamicDataSourceAnnotationAdvisor.class
new file mode 100644
index 0000000000000000000000000000000000000000..288f5f119b1948499a813d954bb892fb3995ea30
GIT binary patch
literal 2327
zcmbtWYi}Dx6g}fd*0G%jE^PvoG%Y1KcG{&BTEHRTI0;R$(~6*qRN}*Uy-AkXJJ#;H
zr9Xv#0TLxZBp#oT_)(NI>y2$9r*4%Go|(OK=RVFocgFwx``hmTZsJ}VIlOP+gB0e{
zh~d^aUcv1&hY$7YBLg32kV478vVl+1NMl70pBnfqjY*XCuxg-UU`=35HXb>aEpV}_
zyggH@wrn;X=~}j4o8@q~B#>$=#|^AbAaEtr^xK}}?(KTAWj|KlL8yH{(xLv?vg10z
ziom^m)lx09E>+8EsE*lq;>wm|nGG38Uv<35(OOr$M(K7aExWD?WZ)=w(+zB@wFBjq
z79R*CDyqSNr>c%?Z*^LA+xtq^o0R0L%970o(sT58BuoVRjxTWMtWjtrd`2L!5T!68
zR)OkSeGX!2pvVP;_g*9ESA*>MA>WpBES&tcy8rLGAf>m$hgr>jlXs;dKY
zOSxN}W|Mhj_Uz!eVziTAe3812^H7%*0&~%kQ%N)F+rg?W-3@86cuxf0%MbNYr;cy#
zcD2lb6JfnGdb?-Bd`Sxe>Gkh4d&nf;zy@)wcbsOUpLyJBTLSTx9@Aa&Z8(}w?>vW;
z5go37D<8=$X7D-T&}*|P-91wy96GSQo^!2rCyR4?{^h5Lh2}QunOiX}6UZn6lSFW}gZ*8Cd&l++n>6pokE`h-9QAm{Qe&CT^$5BMZ6S#ZE5C$4lAU`aOZYedT
z{T>rYw!FT`&gZLr%4`SvJ`D-~KY67oeZTZj>z~_IUd;~nRij@|fro=uy4t6A@=I}p
zcf{Mn8&((j7|bx_WXENH34Hw``a?VT`MfFNGM}~__z>~Mi|H=nTNu+l#5qa%3}*TL
z8oxS-a|O&74k3zvW8w(0om~77i9ZU(r$`nkAA1VpN9x4!I>#Im91EO_w6lauxP~_<
zxzM$Pi+Gb?w1_$G3C_S2#4{d<8MtiV3I%WRX9(_I<$}mzfuoMc8^{Jcd33
zlSBe2@o&O15m*_>ezuqWEYVqFSo743L(C8)5IBMBbix}ginu|UHa2&J^iD35I7GIZ
z%lv|g+7Tvqiien5`We&xRJyLq$Y7Nvu7s}VyA~qX8J7E97DI4<0yo04@b;mP7;gRt
D7I%i>
literal 0
HcmV?d00001
diff --git a/target/classes/com/baomidou/dynamic/datasource/aop/DynamicDataSourceAnnotationInterceptor.class b/target/classes/com/baomidou/dynamic/datasource/aop/DynamicDataSourceAnnotationInterceptor.class
new file mode 100644
index 0000000000000000000000000000000000000000..0acc58d20087c1e70ffe0299be61ce257da738b0
GIT binary patch
literal 3519
zcmbtXX;%|h7=A7!8A(RLfD}-vtsARjtF;OiQ5Hc1Qa}{D*dZCn$Yds+8Bn_K?O(8e
zpkM7d6{S6=?dSd{d-~i-$YMg{ayZ<%bLYM9`n=D*`RCu?{{(OfKSj}o2?di;)M26l
zdvPVo;c65KOvNybYjQRtXYWdpSp{=Z%;UNo7NWR;n=!<&7{x8Tr{Miv_&`oSl$vhG
z@DX%5TZ$oxlmbJ+vOsKZW-M`gW_E0R@}@vMaYtX*HA}Zwv^n23?Ug}+-6M|e`MT{d
z=+>Gca4@xD>lrgSs{8t!v*sp^xvXK$8lGdV8?L};BI#tbCEdxGDQ8W~OKT~Ldx5y-
zQC=JUKP@!7zp9xT-SwoAOD|z0r-LRsD@=@7y5|)`8LnxiB8oB%v=KRP+NM7wP~X+P
zAP^dHQp{mv!nBR)wak*?&g)ASSK0pUMbt#rht6i=_Wwg;b
zZVRvHTC24j1RL3HAhbMf>wM49pn|jllO&+vj=&+$@GH<*-kF!XYI^nzttnyLxs$Q&
z{v3N5Q~3s!hN3x!88>B*^j5@I72+o(iK#e@BLYLUxTr#9Sp%zh4X>+s6Q>lcs<4nz
zV5@MDRq-*7sBqz_@UbS)U(1qST6ES<#X9b)xQ7h|pQ!j0pQ#wc=Pag*FYu+nm6{r#
zx$6bQVHIEDYZb5Jkb-Yie2ec?97Lyr?^XPO9|f9<s!Ek@Nz2gPstz=)7=Dg#1rC($F3%XL
zBIfHZrSs{!@WKqf%~;K*S8Spg*YFJ6mm!p7Bq!Q^i;PXnMQMT4Rm4g*mLR^ki!q#%
zdG)fAOP5_eW88JzRW0ebhE{dQb>Fl|t9zDBJ5|&pK#q9|KZ6wurIo0vobHs@t8hdp
zrZ<+!`oss1ZU!IaCCK%?8>XM$0WuUCt_9Ye33i)0!&!O95tx0h+LlDVjo`{9-kVAxz|DPvBT-33j$i7TwFctw1|M=-}Ue&JXa?TZcIR$wI-L)D%3)xqOBxLk{P7
zly5_*=L~4-c?8k(2kI6dq5dI4zXm&wag9#VTN{Q=&_E}TUp2I%)$ejNxbwFZ_u
z@|LIx+QSb5FJwH&(7^Emtq-FK7wP*Y`Z$7f7{yhLVG-jnFcHKzL8(RN^EB%g
zk=_;}P3I$3pyMr^VN^}H$t;~^Tqil6V}?Q;HJ)tynZfhiE$fn#dWTXnM{THof};wC
z6kOo%pW!Ds!%?AE#jFv!^e%^m0oswZj`Z|CL~9WN%r#g0N@@}*cp3>%#&eMIjaAdr
T^0Xdp2R#y{QqMST)#37g7sleE
literal 0
HcmV?d00001
diff --git a/target/classes/com/baomidou/dynamic/datasource/provider/AbstractJdbcDataSourceProvider.class b/target/classes/com/baomidou/dynamic/datasource/provider/AbstractJdbcDataSourceProvider.class
new file mode 100644
index 0000000000000000000000000000000000000000..3df7d26e13cd8144222bca9638ce42d6e8d951f9
GIT binary patch
literal 4513
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
BeCPlG
literal 0
HcmV?d00001
diff --git a/target/classes/com/baomidou/dynamic/datasource/spel/DefaultDynamicDataSourceSpelResolver.class b/target/classes/com/baomidou/dynamic/datasource/spel/DefaultDynamicDataSourceSpelResolver.class
new file mode 100644
index 0000000000000000000000000000000000000000..c300d802eff8f35a7ccda134cf1486dba7388ac7
GIT binary patch
literal 633
zcmb_ZJxc>Y5Pfq=JQJhQs3|N28%Y%0La>QgXb{9h!ASbOyESgO54n$k|4J*t!XMy|
z5@+uMDFTwh=DnMF^JZsmzJETy0Gy)JKm~0Z+ctJ=>=IVab)>TkLZ#aq5vo_QuLvzi
zN9ryQU6njaH{eX$i9H#NWTH(xOIEXIof2*xFAjw(<52r?F8tR>hT0Rp%w!tpiKj&R
zq5?5cPcjd(K`9Sd9Tw`4#Rrwf!Bi!Ef}ND#gu|{gky9xG8I8p-OLR2u_ZCxxy6HcX
zL0$~H;2|{1m#(#0rMJu=C#FjiHLMVB{%t+N=6t$)ccQ$EaJgLjzkVAIVDVx3etcz%
zndfG-ITFmoTs!&zy%+K-qmh9<)ES#)0UB82h&WznH0CpAi`hDUGl;o!zi@U+b>=h`
N8)&hI_blqSegT|)rCI<0
literal 0
HcmV?d00001
diff --git a/target/classes/com/baomidou/dynamic/datasource/spel/DynamicDataSourceSpelParser.class b/target/classes/com/baomidou/dynamic/datasource/spel/DynamicDataSourceSpelParser.class
new file mode 100644
index 0000000000000000000000000000000000000000..0d5ca2a061722baf4f8a203c5ed12ede74c5bcf8
GIT binary patch
literal 273
zcmaKnJ#GR)427ThTaqeANSQQoK}kb_B1HlPu_rLIqs^e%@oIKJ;%XEeAcu;W4FyG{
zG?w+`_r2%upYsL43=aj00#m}cmDpLr_GP89X3cM^29-&1H%%)brQB65+AbLngdCpA(*!ryz|pOG$Fm%hvi$A0OX(9${g$;hkvX
uDm`#@yXPt!x?d1?*}?yC2v7HBpS!&^X+j_j^3wo~2t$ne4dXlqm|OwWSyZ|J
literal 0
HcmV?d00001
diff --git a/target/classes/com/baomidou/dynamic/datasource/spel/DynamicDataSourceSpelResolver.class b/target/classes/com/baomidou/dynamic/datasource/spel/DynamicDataSourceSpelResolver.class
new file mode 100644
index 0000000000000000000000000000000000000000..7e605cb05fe3947729edea3025bdb7d406ad9ed7
GIT binary patch
literal 235
zcmX^0Z`VEs1_omWPId-%b_Nbc2KJ)V;{2SlR7M6h4WF#UvPAuy#JqI<;F6-uymV_#
zOd&=FuHgLAqU2P!%p9ODC6~&)#N5nem&B4ph8YEBTu&>}sMiHr(^b
literal 0
HcmV?d00001
diff --git a/target/classes/com/baomidou/dynamic/datasource/spring/boot/autoconfigure/DataSourceProperty.class b/target/classes/com/baomidou/dynamic/datasource/spring/boot/autoconfigure/DataSourceProperty.class
new file mode 100644
index 0000000000000000000000000000000000000000..6a1af3de465273daaa32dab7509b448adaf743fb
GIT binary patch
literal 6380
zcmb_fTXS1i75iAN%1SmaD+NN=uOJm361}(SBmSQWGB}bPu
z34sFT4xuf#mO{%tff8s7jRTZn;DIv36AyiY7x)3ZFw8K_P{OzNK9Y{5-iQU^{*p!w4>z_)-ilxDZ7Lo-pxb3}M}QN=Cjc%~z!Psx)7d
z=IhctEzL6~z7gZ^v(kK1!hK87bJ9F7&9|lbjx^tu=6lk7Uz#5X`G+Ph#;_R|EL@V`
zA6fXZ{Jvn}Cl)SS_^E}TS$NUHOBPIxO{x&d2??}Y4Kg9;
za3x>PE@qBrOWB!RW>-F6D5uKVLcU~R|G`3W&Wm@V$mE#Sf)31}<;p2;!LJ^G{sb9*9x<#+;N7LzBd>u&u5wY)D5gteb0O!5TDDG
zr)z@g8QSLC_L^i&l8!3Xbgv*(bu-#LdOfuy7;d6bFcA(O6U|6Q$7-@s`PGyoy#qDz
zSSpUv&mm^8z6y#mxZXemH+#{qyS?#}eTXXhQuS^9c2U
zn3t$Jo#NH>bWfS|9bv%MwraQSNI5mTFqv9XwZ%t-zSCz@`8~4gygcVqrFngI@E+OE
zMV&spe{v63oj6j=lq$J0Z*t#ah6nZ9bq+SIPiRoD&0zi0=~?^A=wSVWBJ@`2n}gL{
zt#UzM5e8!VG4McEF0lUQ!|HZMOZR{@4@z@Tnn`J!2hKAW4T8mbo4P8(OSY``2HkX={Zt1QRSfricBNwtg)aQg}3
z1l}R3dsPYOUR4C_SrUgbAdHR$4k?#TIJ&=zMV(-dXMtS&YdP|k_H6Br`#A<;>c$H#A0eT`!>_=4iJ%4dv6b9_+kDR9nlq(FmgMDk
zjy5`v1UT#E+Q;COD%-{&vBn_DfFOoQJis~L=)679nWYinY&SaJ73j>83UF>~bRG|M
zW+?_Zw>LW98|cgu4sZ@NI!^>Tv-AU;%|_?_fzF3<#B(0!zPE7S&Eb(Nu!bAmw<`BO
zP4VPHvML!-*-;$xgfr<66jgy*eY#sMkgmDo%s>m;WEI}Yz;|$@1@9qxZ*Z=$HRmd2
zEV(`u94Nl#KynU9pofD4*=r6Y2Z;oFUvQwdH3yQDNCLe-I8ghV1IbY)fj)o_vXvTM
zA&k(P1L?ESz=!ZiP#|;7f%E}t$W^EVwfvca=;cwjFfx1*;n3xg-=pJMgj+9<{0<$H
zqr=PSR9%9usZlm=XzY)OJE7OmbqV&E6Iw>1%IJ2(q;$IxCoG)EYe-x|n-g{-K2ncs
zlGNi`jwvL|BbkonBlWsbl6u{k6BSa-BSoEJyM6$=_5IA7fFtraJqz)@JL-w!bjTZc9XQx?Qyz=
z)Z>x5ot`QwbeTeEuHx7AHdK!TV*#^BbCY_FVrYYbwZ
zD2z#C3$jEJ%V9>arO=LnK;Kk%XkADG>on<$5!$IrVRPsBJPX0<9JvH@Y#Ey#k@0RfBnBtsSu80JZR&Bu
z%EZc0PL>m{ntI)cGDT`8){FM)b4_Jpsd!#y)zt4=%4F3{EFkT*!Hp^tYsd47R!xo@
zQ>IwW#EQ~h8{N1vv6wusxH4@H7VJ5_B%WYf@h^N7k8#1m_$NL_)Iy2<10UyNw&E6w
z?h`~IKGlAO$BDwcIiANSi6RuzqfseV*5Jm9^J{dnt6vN-pkIxas
zMOH1XNL=GUh_W&aN(qK>jZ@Y8Ei%xHaFtNygjNoDw1|&ZXEu&{WOF6C&JQqnE>@FE
z-7DDUIYxsV>%Oa+J@?ou?)3=QV|YR0s|Tsac@vTs%D!%>dbBs^F(Bo}|9Nzk;vyv{
zukrJ*Vl!X+Z%J%f##Sj-{v-x8?q0@CiJLX%iM%y&i^jcz2Q}^!e5=O&g5Rp~2En&!
f>`0s;jW-J3M!bwwE@J%(JMWc>fiI|&=!^dcJ9=n+
literal 0
HcmV?d00001
diff --git a/target/classes/com/baomidou/dynamic/datasource/spring/boot/autoconfigure/DynamicDataSourceAutoConfiguration.class b/target/classes/com/baomidou/dynamic/datasource/spring/boot/autoconfigure/DynamicDataSourceAutoConfiguration.class
new file mode 100644
index 0000000000000000000000000000000000000000..ee1184649d25c3bf4fe4020ba1042a80885a60d1
GIT binary patch
literal 6116
zcmb_g>wgqi8Ga@t%rY4)4Nxv^ArxCeZlg$JC5Yw*{8HILysr5aXp-}>={kZPte*Z_Oxjm5yGzCZ^q5k0cu#cdqhHI
zhZQj-+|z5ujsEoHm|;JzQ<|fCSdWe9wkiI5ot3GRCdEJb|5RF#>+o#i=qGgd?6}A@
zQ)a}lC7h`XleI?ridMlmUdfuY#`oeCXY5rw7Q7MU`W7K8jB!S+ig3|eJr3K?eapl&Cb
zsRHe=Ji?HXv|>}l2#yHdO88m$G@@VbFVfo$lLA)>?JHpG=_}#Ek|J`-loJ|dm_$Og
z$py*Oo?uFm&>P4+z(hR-G@41)b1`serNCY^i8WEi(q3NmynVY@1e5av`God|W8OBT
zxUtY}icM#iFP?q7L$gQ;5?V^8z7naD3D4PXb6d+@a%OHe^Mkj)Yh7`%`z^v4%zvdK
zRa1H_P2&4Y(kYRNi}f+ujd9C12-8#U^oht=xF{7CqvaH2p(1LQCAC3Lx1vp?XEI^g
zDM~j218w;lCSs?}h}J2dKHn`eTdRsk(ITNMs9wrv=h4ZS50b`rHenT?#U6opiN#P5
zq7TK}tz}$R@iKm@;%B&`;uXBA;x)WpKB6!6tN1zIQ1J`Asp6OTm5R6Uwu)clH!7~8
zMa6INj*Q=__&xq0VF!6PCt8w;nPwv%W&PDGnu9HcokYgFD&E7a3Jsr;P@BDQb>Ym}
zh0C)GFTJ~P^I}u>+_g{6ULwTI!t)oi7v7NZzKRd-Er(-E!Y!z>6Ju61a17
zjFDTe5-ycf(3GtJalH&3T;=#k7ohs;wv1hQ`R^mtaEo;Galq|>drU-Q&9
zlA6n^_=AL1wK`G0ROe}A1h~kk)y=qHdL|&ter>2X#Iy+)i8(3S#}hIv^ya8xdS~A
zPQd|uiC}`6xOn_B-);P{l0iHF3;3t`7Vx$6s2ZKa>fQz+BLg{ukk?$3fznWrSVKa<
zA?nzJ^*D@eI8r3N){`E>=4GXKpwpB7FRXIVj?bf-($&63SNhrvKIJv<$zWY$Lk9OY
zW>DjPU7x{*E7(=D@jC81_5n84Y`%dl6`04?(Z)I4Kie<*9=w5V6=NI3$rgO;hFWdM5PKLlANx`jish=*NI(k4r?Z;@swWY^ObH`0EgS3hpKYREV^F#BfBjeqLIB~-};mCEv
zJLJjr;|J36~H&q5+h#twUy&VoaU`e~s@aIqInskira@r}J$cWBGRYzkH*6*8l(j
literal 0
HcmV?d00001
diff --git a/target/classes/com/baomidou/dynamic/datasource/spring/boot/autoconfigure/DynamicDataSourceProperties.class b/target/classes/com/baomidou/dynamic/datasource/spring/boot/autoconfigure/DynamicDataSourceProperties.class
new file mode 100644
index 0000000000000000000000000000000000000000..3198381ca24221941b9b32e7376eb6b2fe4bba40
GIT binary patch
literal 3932
zcmcguYj+b>6y1}wNtzCnhEha%79VY@9Tmh16`>EL5NM@PUcPRVX*z8(6K5va`pK{U
z8(qsRSh|)!z#rvu-?=l%4qy5ovN`WoT^oF>PBhD7FDZgv@94NouTzL$MFqO_no3+uUloJ8}oEyC2(We
zb!w*T?_9Y``x(!7g>RPW{&39RTt#>uw;y$`%}nm^Lx^b1EB{)S8I-_QV7cFMOQx&g
zXw1Z-O;=2phWl%myc(T~@6I|-#T2&OExC28q~Xr~&g>eH0K%A;KyyKqh+m0`M%dtHTiv`CmhXG!9Mb-S#ako^Y8D-zx_Kli~tYvz}UDNZ;5V+1$
z6Qdb-4XF)lOSqPXv%vv=65HFRYp6xzX0X@vDK%r+mVZ@4a(rS{L*JZJ3YcWs=G}UA
z&2;Yzx+>Y{6h&o~uyP(Q_W2tYeSi2r;?$MJ@EklPBbF_j{&G|RBjXdXWHw9S5M?9@
zqAD1U#A0>eb*{Y@_7Bpth?L}7%wQ3*WhUVU{%kf8%hst%5|*=bdR6j@fq&@R#{
z2PqN|S;G=hUcO26s)+%DD@tk@3(@x^Y}SiW;@EgMBP5LvQ7F!dTqxJ1gcKTWr}R!O
zqP5>4{Tj$3{TZawExL@vkEYlng`RdTzbd*&^bB1H2{Rfu6!9gJ2^rHS6A>no2`RHY
z{z@4m(Ff>d#F_I7ehjjXzxZdkIFo!z77OvyV|!@_^+#;TdN_hHq)QZ?6Hx3<~(
z)zvvwYBs8=@P5^i$0U1pRj{SII*#KF4abA4K45FXvbW6AP2p|uO4o4$Z}MW=w+5q2
zvfzl)tYF6}nq8-kxTfP2PBSdME}){r%ROL($;Zl;jtZ(e&f;7ewwyRR#&BN4?R`Bu
z_)V$fZM>u5w1nI}uR6vtq2a;H8}157>*~>Pr1jWZTH7>>K3_1crLZ3OJbNZ8b#rN*
z-DG?*emzAM)20@dh!lPj7mi8?=lCcb*{!FxY^ePrksR1`bnVh!RH{80Ij?;n4<0ehUnK!0#9`{7&*g{2?E|7kRX49%F{t
zy+)(+_!NtnqJ*wY!=M~E{s%vFApWNMK@$b}i
literal 0
HcmV?d00001
diff --git a/target/classes/com/baomidou/dynamic/datasource/spring/boot/autoconfigure/druid/DruidConfig.class b/target/classes/com/baomidou/dynamic/datasource/spring/boot/autoconfigure/druid/DruidConfig.class
new file mode 100644
index 0000000000000000000000000000000000000000..b9fcfabed14d5b4d8d9455d0b473e786cf9132e6
GIT binary patch
literal 27451
zcmeHvd3+qjv43^Xu6HD@uGKlZZOgW7>%g}e`H~OWGQRK$=3L8bYw=pLrIn2dhryc4o(wDLU=h}f(h?i)3ZCH)vQ>E?cYB?K74kn
zyS`Oj-P2uDQ#JDU|Mln-L^MfW6A<4Eh^Mnjii25nnRq4}KhI{1=fwB<=Lfp@VYYZ)
z{D=WRX21&!_)lH@gd0EQ#?N%|A~*hv8!u&xpR?32xaVc=`ENf4!hi3a$*f=M;#bW2
zHM4%hJ+J8ERqlC>dtTSY8{Bx48;6u+<<2>}c#C^~%e`+~y<+zzyLIsn_x_H1f1fS>
zAl~I44E{%5yvLmXVa}g)@n>E9h1-AS_TP9uf7iwTa?d}w=bu>+dtVoax#t7!`Ijy}
zL_-o9Qs`20L(}PZkd?lG^k>sTaS%Upm@Wf+)peQ0plp`NfkGM7WiI#RaZkQ33%F6p
zjgT&jxKYfF5?z*Zql_Enx-_^^!Hr7)hxUKEtm58k?yb>fEjQ}8F