目录
二、准备工作
3.1 配置文件 application.properties
一、应用场景
项目需要从自己的数据库上读取和管理数据外,还有一部分业务涉及到其他多个数据库。
为了能够灵活地指定具体的数据库,本文基于注解和AOP的方法实现多数据源自动切换。在使用过程中,只需要添加注解就可以使用,简单方便。
二、准备工作
2.1 创建数据表
1.
2.
CREATE TABLE `user` (
3.
`id` int(11) NOT NULL AUTO_INCREMENT,
4.
`name` varchar(255) NOT NULL,
5.
`age` int(11) NOT NULL,
6.
PRIMARY KEY (`id`)
7.
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8
8.
9.
10.
USE test1;
11.
CREATE TABLE `teacher` (
12.
`tid` int(11) NOT NULL AUTO_INCREMENT,
13.
`tname` varchar(255) NOT NULL,
14.
`tage` int(11) NOT NULL,
15.
PRIMARY KEY (`tid`)
16.
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8
17.
18.
19.
20.
USE test2;
21.
CREATE TABLE `student` (
22.
`sid` int(11) NOT NULL AUTO_INCREMENT,
23.
`sname` varchar(255) NOT NULL,
24.
`sage` int(11) NOT NULL,
25.
PRIMARY KEY (`sid`)
26.
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8
2.2 添加依赖
mysql:5.1.44
mybatis:1.3.2
druid:1.1.3
1.
<?xml version="1.0" encoding="UTF-8"?>
2.
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
3.
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
4.
<modelVersion>4.0.0</modelVersion>
5.
6.
<groupId>com.example</groupId>
7.
<artifactId>dynamic-data-source</artifactId>
8.
<version>0.0.1-SNAPSHOT</version>
9.
<packaging>jar</packaging>
10.
11.
<name>dynamic-data-source</name>
12.
<description>Demo project for Spring Boot</description>
13.
14.
<parent>
15.
<groupId>org.springframework.boot</groupId>
16.
<artifactId>spring-boot-starter-parent</artifactId>
17.
<version>1.5.8.RELEASE</version>
18.
<relativePath/> <!-- lookup parent from repository -->
19.
</parent>
20.
21.
<properties>
22.
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
23.
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
24.
<java.version>1.8</java.version>
25.
</properties>
26.
27.
<dependencies>
28.
<dependency>
29.
<groupId>org.springframework.boot</groupId>
30.
<artifactId>spring-boot-starter-web</artifactId>
31.
</dependency>
32.
33.
<!--mysql-->
34.
<dependency>
35.
<groupId>mysql</groupId>
36.
<artifactId>mysql-connector-java</artifactId>
37.
<scope>runtime</scope>
38.
</dependency>
39.
<!--mybatis-->
40.
<dependency>
41.
<groupId>org.mybatis.spring.boot</groupId>
42.
<artifactId>mybatis-spring-boot-starter</artifactId>
43.
<version>1.3.2</version>
44.
</dependency>
45.
<!--aop-->
46.
<dependency>
47.
<groupId>org.springframework.boot</groupId>
48.
<artifactId>spring-boot-starter-aop</artifactId>
49.
</dependency>
50.
<!--数据库连接池-->
51.
<dependency>
52.
<groupId>com.alibaba</groupId>
53.
<artifactId>druid</artifactId>
54.
<version>1.1.3</version>
55.
</dependency>
56.
57.
<dependency>
58.
<groupId>org.springframework.boot</groupId>
59.
<artifactId>spring-boot-starter-test</artifactId>
60.
<scope>test</scope>
61.
</dependency>
62.
</dependencies>
63.
64.
<build>
65.
<plugins>
66.
<plugin>
67.
<groupId>org.springframework.boot</groupId>
68.
<artifactId>spring-boot-maven-plugin</artifactId>
69.
</plugin>
70.
<!-- mybatis generator 自动生成代码插件 -->
71.
<plugin>
72.
<groupId>org.mybatis.generator</groupId>
73.
<artifactId>mybatis-generator-maven-plugin</artifactId>
74.
<version>1.3.2</version>
75.
<configuration>
76.
<overwrite>true</overwrite>
77.
<verbose>true</verbose>
78.
</configuration>
79.
</plugin>
80.
</plugins>
81.
</build>
82.
</project>
2.3 生成 bean、dao、mapper
使用MyBatis Generator自动生成,方法如下:
三、动态数据源
3.1 配置文件 application.properties
1.
2.
custom.datasource.names=ds1,ds2
3.
4.
# 默认数据源
5.
custom.datasource.driver-class-name=com.mysql.jdbc.Driver
6.
custom.datasource.url=jdbc:mysql://localhost:3306/test
7.
custom.datasource.username=root
8.
custom.datasource.password=root
9.
10.
# 更多数据源
11.
custom.datasource.ds1.driver-class-name=com.mysql.jdbc.Driver
12.
custom.datasource.ds1.url=jdbc:mysql://localhost:3306/test1
13.
custom.datasource.ds1.username=root
14.
custom.datasource.ds1.password=root
15.
16.
custom.datasource.ds2.driver-class-name=com.mysql.jdbc.Driver
17.
custom.datasource.ds2.url=jdbc:mysql://localhost:3306/test2
18.
custom.datasource.ds2.username=root
19.
custom.datasource.ds2.password=root
20.
21.
22.
custom.datasource.filters=stat
23.
custom.datasource.maxActive=100
24.
custom.datasource.initialSize=1
25.
custom.datasource.minIdle=1
26.
custom.datasource.timeBetweenEvictionRunsMillis=60000
27.
custom.datasource.minEvictableIdleTimeMillis=300000
28.
custom.datasource.validationQuery=select 'x'
29.
custom.datasource.testWhileIdle=true
30.
custom.datasource.testOnBorrow=false
31.
custom.datasource.testOnReturn=false
32.
custom.datasource.poolPreparedStatements=true
33.
custom.datasource.maxOpenPreparedStatements=100
34.
35.
mybatis.type-aliases-package=com.example.demo.model.*
36.
mybatis.mapper-locations=classpath:mapper/**/*.xml
3.2 动态数据源核心代码
1.
2.
DynamicDataSourceAspect:利用AOP切面实现数据源的动态切换;
3.
DynamicDataSourceContextHolder:动态切换数据源;
4.
DynamicDataSourceRegister:动态数据源注册;
5.
TargetDataSource:在方法上使用,用于指定使用哪个数据源。
6.
package com.example.demo.datasource;
7.
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
8.
9.
/**
10.
* 动态数据源
11.
*/
12.
public class DynamicDataSource extends AbstractRoutingDataSource {
13.
@Override
14.
protected Object determineCurrentLookupKey() {
15.
return DynamicDataSourceContextHolder.getDataSourceType();
16.
}
17.
}
18.
package com.example.demo.datasource;
19.
20.
import org.aspectj.lang.JoinPoint;
21.
import org.aspectj.lang.annotation.After;
22.
import org.aspectj.lang.annotation.Aspect;
23.
import org.aspectj.lang.annotation.Before;
24.
import org.slf4j.Logger;
25.
import org.slf4j.LoggerFactory;
26.
import org.springframework.core.annotation.Order;
27.
import org.springframework.stereotype.Component;
28.
29.
/**
30.
* 切换数据源Advice
31.
*/
32.
@Aspect
33.
@Order(-1)// 保证该AOP在@Transactional之前执行
34.
@Component
35.
public class DynamicDataSourceAspect {
36.
private static final Logger logger = LoggerFactory.getLogger(DynamicDataSourceAspect.class);
37.
38.
@Before("@annotation(ds)")
39.
public void changeDataSource(JoinPoint point, TargetDataSource ds) throws Throwable {
40.
String dsId = ds.name();
41.
if (!DynamicDataSourceContextHolder.containsDataSource(dsId)) {
42.
logger.error("数据源[{}]不存在,使用默认数据源 > {}", ds.name(), point.getSignature());
43.
}else {
44.
logger.debug("Use DataSource : {} > {}", dsId, point.getSignature());
45.
DynamicDataSourceContextHolder.setDataSourceType(dsId);
46.
}
47.
48.
}
49.
@After("@annotation(ds)")
50.
public void restoreDataSource(JoinPoint point, TargetDataSource ds) {
51.
logger.debug("Revert DataSource : {} > {}", ds.name(), point.getSignature());
52.
DynamicDataSourceContextHolder.clearDataSourceType();
53.
}
54.
}
55.
package com.example.demo.datasource;
56.
57.
import java.util.ArrayList;
58.
import java.util.List;
59.
60.
public class DynamicDataSourceContextHolder {
61.
private static final ThreadLocal<String> contextHolder = new ThreadLocal<>();
62.
public static List<String> dataSourceIds = new ArrayList<>();
63.
64.
public static void setDataSourceType(String dataSourceType) {
65.
contextHolder.set(dataSourceType);
66.
}
67.
68.
public static String getDataSourceType() {
69.
return contextHolder.get();
70.
}
71.
72.
public static void clearDataSourceType() {
73.
contextHolder.remove();
74.
}
75.
76.
/**
77.
* 判断指定DataSrouce当前是否存在
78.
*/
79.
public static boolean containsDataSource(String dataSourceId){
80.
return dataSourceIds.contains(dataSourceId);
81.
}
82.
}
83.
package com.example.demo.datasource;
84.
85.
import org.slf4j.Logger;
86.
import org.slf4j.LoggerFactory;
87.
import org.springframework.beans.MutablePropertyValues;
88.
import org.springframework.beans.PropertyValues;
89.
import org.springframework.beans.factory.annotation.Value;
90.
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
91.
import org.springframework.beans.factory.support.GenericBeanDefinition;
92.
import org.springframework.boot.autoconfigure.jdbc.DataSourceBuilder;
93.
import org.springframework.boot.bind.RelaxedDataBinder;
94.
import org.springframework.boot.bind.RelaxedPropertyResolver;
95.
import org.springframework.context.EnvironmentAware;
96.
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
97.
import org.springframework.core.convert.ConversionService;
98.
import org.springframework.core.convert.support.DefaultConversionService;
99.
import org.springframework.core.env.Environment;
100.
import org.springframework.core.type.AnnotationMetadata;
101.
102.
import javax.sql.DataSource;
103.
import java.util.HashMap;
104.
import java.util.Map;
105.
106.
/**
107.
* 动态数据源注册
108.
@Import(DynamicDataSourceRegister.class)
109.
*/
110.
public class DynamicDataSourceRegister
111.
implements ImportBeanDefinitionRegistrar, EnvironmentAware {
112.
113.
private static final Logger logger = LoggerFactory.getLogger(DynamicDataSourceRegister.class);
114.
private ConversionService conversionService = new DefaultConversionService();
115.
private PropertyValues dataSourcePropertyValues;
116.
117.
// 如配置文件中未指定数据源类型,使用该默认值
118.
private static final Object DATASOURCE_TYPE_DEFAULT = "com.alibaba.druid.pool.DruidDataSource";
119.
120.
// 数据源
121.
private DataSource defaultDataSource;
122.
private Map<String, DataSource> customDataSources = new HashMap<>();
123.
124.
private static String DB_NAME = "names";
125.
private static String DB_DEFAULT_VALUE = "custom.datasource"; //配置文件中前缀
126.
@Value("${bi.datasource.defaultname}")
127.
private String defaultDbname;
128.
129.
//加载多数据源配置
130.
@Override
131.
public void setEnvironment(Environment env) {
132.
initDefaultDataSource(env);
133.
initCustomDataSources(env);
134.
}
135.
136.
//初始化主数据源
137.
private void initDefaultDataSource(Environment env) {
138.
// 读取主数据源
139.
RelaxedPropertyResolver propertyResolver = new RelaxedPropertyResolver(env, DB_DEFAULT_VALUE+".");
140.
Map<String, Object> dsMap = new HashMap<>();
141.
dsMap.put("type", propertyResolver.getProperty("type"));
142.
dsMap.put("driver-class-name", propertyResolver.getProperty("driver-class-name"));
143.
dsMap.put("url", propertyResolver.getProperty("url"));
144.
dsMap.put("username", propertyResolver.getProperty("username"));
145.
dsMap.put("password", propertyResolver.getProperty("password"));
146.
147.
defaultDataSource = buildDataSource(dsMap);
148.
customDataSources.put(defaultDbname,defaultDataSource);//默认数据源放到动态数据源里
149.
dataBinder(defaultDataSource, env);
150.
}
151.
152.
153.
//为DataSource绑定更多数据
154.
private void dataBinder(DataSource dataSource, Environment env) {
155.
RelaxedDataBinder dataBinder = new RelaxedDataBinder(dataSource);
156.
//dataBinder.setValidator(new LocalValidatorFactory().run(this.applicationContext));
157.
dataBinder.setConversionService(conversionService);
158.
dataBinder.setIgnoreNestedProperties(false);//false
159.
dataBinder.setIgnoreInvalidFields(false);//false
160.
dataBinder.setIgnoreUnknownFields(true);//true
161.
if (dataSourcePropertyValues == null) {
162.
Map<String, Object> rpr = new RelaxedPropertyResolver(env, DB_DEFAULT_VALUE).getSubProperties(".");
163.
Map<String, Object> values = new HashMap<String, Object>(rpr);
164.
// 排除已经设置的属性
165.
values.remove("type");
166.
values.remove("driver-class-name");
167.
values.remove("url");
168.
values.remove("username");
169.
values.remove("password");
170.
dataSourcePropertyValues = new MutablePropertyValues(values);
171.
}
172.
dataBinder.bind(dataSourcePropertyValues);
173.
}
174.
175.
//初始化更多数据源
176.
private void initCustomDataSources(Environment env) {
177.
// 读取配置文件获取更多数据源,也可以通过defaultDataSource读取数据库获取更多数据源
178.
RelaxedPropertyResolver propertyResolver = new RelaxedPropertyResolver(env,DB_DEFAULT_VALUE+".");
179.
String dsPrefixs = propertyResolver.getProperty(DB_NAME);
180.
for (String dsPrefix : dsPrefixs.split(",")) {// 多个数据源
181.
Map<String, Object> dsMap = propertyResolver.getSubProperties(dsPrefix + ".");
182.
DataSource ds = buildDataSource(dsMap);
183.
customDataSources.put(dsPrefix, ds);
184.
dataBinder(ds, env);
185.
}
186.
}
187.
188.
@Override
189.
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
190.
Map<Object, Object> targetDataSources = new HashMap<Object, Object>();
191.
// 将主数据源添加到更多数据源中
192.
targetDataSources.put("dataSource", defaultDataSource);
193.
DynamicDataSourceContextHolder.dataSourceIds.add("dataSource");
194.
// 添加更多数据源
195.
targetDataSources.putAll(customDataSources);
196.
for (String key : customDataSources.keySet()) {
197.
DynamicDataSourceContextHolder.dataSourceIds.add(key);
198.
}
199.
200.
// 创建DynamicDataSource
201.
GenericBeanDefinition beanDefinition = new GenericBeanDefinition();
202.
beanDefinition.setBeanClass(DynamicDataSource.class);
203.
beanDefinition.setSynthetic(true);
204.
MutablePropertyValues mpv = beanDefinition.getPropertyValues();
205.
mpv.addPropertyValue("defaultTargetDataSource", defaultDataSource);
206.
mpv.addPropertyValue("targetDataSources", targetDataSources);
207.
registry.registerBeanDefinition("dataSource", beanDefinition);
208.
209.
logger.info("Dynamic DataSource Registry");
210.
}
211.
212.
//创建DataSource
213.
@SuppressWarnings("unchecked")
214.
public DataSource buildDataSource(Map<String, Object> dsMap) {
215.
try {
216.
Object type = dsMap.get("type");
217.
if (type == null)
218.
type = DATASOURCE_TYPE_DEFAULT;// 默认DataSource
219.
220.
Class<? extends DataSource> dataSourceType;
221.
dataSourceType = (Class<? extends DataSource>) Class.forName((String) type);
222.
223.
String driverClassName = dsMap.get("driver-class-name").toString();
224.
String url = dsMap.get("url").toString();
225.
String username = dsMap.get("username").toString();
226.
String password = dsMap.get("password").toString();
227.
228.
DataSourceBuilder factory = DataSourceBuilder.create().driverClassName(driverClassName).url(url)
229.
.username(username).password(password).type(dataSourceType);
230.
return factory.build();
231.
} catch (ClassNotFoundException e) {
232.
e.printStackTrace();
233.
}
234.
return null;
235.
}
236.
}
237.
package com.example.demo.datasource;
238.
239.
import java.lang.annotation.Documented;
240.
import java.lang.annotation.ElementType;
241.
import java.lang.annotation.Retention;
242.
import java.lang.annotation.RetentionPolicy;
243.
import java.lang.annotation.Target;
244.
245.
// 在方法上使用,用于指定使用哪个数据源
246.
@Target({ ElementType.METHOD, ElementType.TYPE })
247.
@Retention(RetentionPolicy.RUNTIME)
248.
@Documented
249.
public @interface TargetDataSource {
250.
String name();
251.
}
3.3 启动类添加注解
添加注解 @Import :注册动态多数据源;
添加 @MapperScan :将项目中对应的mapper类的路径加进来
1.
2.
3.
import com.example.demo.datasource.DynamicDataSourceRegister;
4.
import org.mybatis.spring.annotation.MapperScan;
5.
import org.springframework.boot.SpringApplication;
6.
import org.springframework.boot.autoconfigure.SpringBootApplication;
7.
import org.springframework.context.annotation.Import;
8.
9.
@SpringBootApplication
10.
@Import({DynamicDataSourceRegister.class}) // 注册动态多数据源
11.
@MapperScan("com.example.demo.dao")//将项目中对应的mapper类的路径加进来就可以了
12.
public class DynamicDataSourceApplication {
13.
public static void main(String[] args) {
14.
SpringApplication.run(DynamicDataSourceApplication.class, args);
15.
}
16.
}
四、使用方法
4.1 Controller
1.
2.
3.
import com.example.demo.model.Student;
4.
import com.example.demo.model.Teacher;
5.
import com.example.demo.model.User;
6.
import com.example.demo.service.DynamicDataSourceService;
7.
import org.springframework.beans.factory.annotation.Autowired;
8.
import org.springframework.web.bind.annotation.PathVariable;
9.
import org.springframework.web.bind.annotation.RequestMapping;
10.
import org.springframework.web.bind.annotation.RestController;
11.
12.
import java.util.List;
13.
14.
@RestController
15.
@RequestMapping(value = "/dds")
16.
public class DynamicDataSourceController {
17.
18.
@Autowired
19.
private DynamicDataSourceService service;
20.
21.
@RequestMapping(value = "/user/{id}")
22.
public User getAllUserData(@PathVariable Integer id){
23.
return service.getUserData(id);
24.
}
25.
26.
@RequestMapping(value = "/teacher/{id}")
27.
public Teacher getAllTeacherData(@PathVariable Integer id) {
28.
return service.getTeacherData(id);
29.
}
30.
31.
@RequestMapping(value = "/student/{id}")
32.
public Student getAllStudentData(@PathVariable Integer id) {
33.
return service.getStudentData(id);
34.
}
35.
}
4.2 Service
注解@TargetDataSource 不能直接在接口类Mapper上使用,所以在Service上使用。
1.
2.
3.
import com.example.demo.dao.StudentMapper;
4.
import com.example.demo.dao.TeacherMapper;
5.
import com.example.demo.dao.UserMapper;
6.
import com.example.demo.datasource.TargetDataSource;
7.
import com.example.demo.model.Student;
8.
import com.example.demo.model.Teacher;
9.
import com.example.demo.model.User;
10.
import org.springframework.beans.factory.annotation.Autowired;
11.
import org.springframework.stereotype.Service;
12.
import java.util.List;
13.
14.
@Service
15.
public class DynamicDataSourceService {
16.
17.
@Autowired
18.
private UserMapper userMapper;
19.
@Autowired
20.
private TeacherMapper teacherMapper;
21.
@Autowired
22.
private StudentMapper studentMapper;
23.
24.
25.
//不指定数据源使用默认数据源
26.
public User getUserData(Integer id) {
27.
return userMapper.selectByPrimaryKey(id);
28.
}
29.
30.
//指定数据源-ds1
31.
@TargetDataSource(name="ds1")
32.
public Teacher getTeacherData(Integer id) {
33.
return teacherMapper.selectByPrimaryKey(id);
34.
}
35.
36.
//指定数据源-ds2
37.
@TargetDataSource(name="ds2")
38.
public Student getStudentData(Integer id) {
39.
return studentMapper.selectByPrimaryKey(id);
40.
}
41.
}
五、测试
- localhost:8080//dds/user/1
- localhost:8080//dds/teacher/1
- localhost:8080//dds/student/1
六、Springboot2.0动态多数据源切换
Springboot 1.x 到 Springboot 2.0配置变化有一点变化。主要是 RelaxedPropertyResolver不再可以Environment自动处理。
主要 是 DynamicDataSourceRegister 中有部分方法不一样。其他方法都不需要修改。
1.
2.
3.
import org.slf4j.Logger;
4.
import org.slf4j.LoggerFactory;
5.
import org.springframework.beans.MutablePropertyValues;
6.
import org.springframework.beans.factory.annotation.Value;
7.
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
8.
import org.springframework.beans.factory.support.GenericBeanDefinition;
9.
import org.springframework.boot.jdbc.DataSourceBuilder;
10.
import org.springframework.context.EnvironmentAware;
11.
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
12.
import org.springframework.core.env.Environment;
13.
import org.springframework.core.type.AnnotationMetadata;
14.
15.
import javax.sql.DataSource;
16.
import java.util.HashMap;
17.
import java.util.Map;
18.
19.
/**
20.
* 动态数据源注册<br/>
21.
@Import(DynamicDataSourceRegister.class)
22.
*/
23.
public class DynamicDataSourceRegister
24.
implements ImportBeanDefinitionRegistrar, EnvironmentAware {
25.
26.
private static final Logger logger = LoggerFactory.getLogger(DynamicDataSourceRegister.class);
27.
28.
// 如配置文件中未指定数据源类型,使用该默认值
29.
private static final Object DATASOURCE_TYPE_DEFAULT = "com.alibaba.druid.pool.DruidDataSource";
30.
31.
// 数据源
32.
private DataSource defaultDataSource;
33.
private Map<String, DataSource> customDataSources = new HashMap<>();
34.
35.
private static String DB_NAME = "names";
36.
private static String DB_DEFAULT_VALUE = "custom.datasource";
37.
@Value("${bi.datasource.defaultname}")
38.
private String defaultDbname;
39.
40.
/**
41.
* 加载多数据源配置
42.
*/
43.
@Override
44.
public void setEnvironment(Environment env) {
45.
initDefaultDataSource(env);
46.
initCustomDataSources(env);
47.
}
48.
49.
/**
50.
* 1.5.8 初始化主数据源
51.
*/
52.
// private void initDefaultDataSource(Environment env) {
53.
// // 读取主数据源
54.
// RelaxedPropertyResolver propertyResolver = new RelaxedPropertyResolver(env, DB_DEFAULT_VALUE+".");
55.
// Map<String, Object> dsMap = new HashMap<>();
56.
// dsMap.put("type", propertyResolver.getProperty("type"));
57.
// dsMap.put("driver-class-name", propertyResolver.getProperty("driver-class-name"));
58.
// dsMap.put("url", propertyResolver.getProperty("url"));
59.
// dsMap.put("username", propertyResolver.getProperty("username"));
60.
// dsMap.put("password", propertyResolver.getProperty("password"));
61.
//
62.
// defaultDataSource = buildDataSource(dsMap);
63.
// customDataSources.put(defaultDbname,defaultDataSource);//默认数据源放到动态数据源里
64.
// dataBinder(defaultDataSource, env);
65.
// }
66.
/**
67.
* 2.0.4 初始化主数据源
68.
*/
69.
private void initDefaultDataSource(Environment env) {
70.
// 读取主数据源
71.
Map<String, Object> dsMap = new HashMap<>();
72.
dsMap.put("type", env.getProperty(DB_DEFAULT_VALUE + "." + "type"));
73.
dsMap.put("driver-class-name", env.getProperty(DB_DEFAULT_VALUE + "." + "driver-class-name"));
74.
dsMap.put("url", env.getProperty(DB_DEFAULT_VALUE + "." + "url"));
75.
dsMap.put("username", env.getProperty(DB_DEFAULT_VALUE + "." + "username"));
76.
dsMap.put("password", env.getProperty(DB_DEFAULT_VALUE + "." + "password"));
77.
defaultDataSource = buildDataSource(dsMap);
78.
// customDataSources.put(defaultDbname,defaultDataSource);//默认数据源放到动态数据源里
79.
// dataBinder(defaultDataSource, env);
80.
}
81.
82.
83.
/**
84.
* 为DataSource绑定更多数据
85.
*
86.
*/
87.
// private void dataBinder(DataSource dataSource, Environment env) {
88.
// RelaxedDataBinder dataBinder = new RelaxedDataBinder(dataSource);
89.
// //dataBinder.setValidator(new LocalValidatorFactory().run(this.applicationContext));
90.
// dataBinder.setConversionService(conversionService);
91.
// dataBinder.setIgnoreNestedProperties(false);//false
92.
// dataBinder.setIgnoreInvalidFields(false);//false
93.
// dataBinder.setIgnoreUnknownFields(true);//true
94.
// if (dataSourcePropertyValues == null) {
95.
// Map<String, Object> rpr = new RelaxedPropertyResolver(env, DB_DEFAULT_VALUE).getSubProperties(".");
96.
// Map<String, Object> values = new HashMap<String, Object>(rpr);
97.
// // 排除已经设置的属性
98.
// values.remove("type");
99.
// values.remove("driver-class-name");
100.
// values.remove("url");
101.
// values.remove("username");
102.
// values.remove("password");
103.
// dataSourcePropertyValues = new MutablePropertyValues(values);
104.
// }
105.
// dataBinder.bind(dataSourcePropertyValues);
106.
// }
107.
108.
// 初始化更多数据源
109.
private void initCustomDataSources(Environment env) {
110.
// 读取配置文件获取更多数据源,也可以通过defaultDataSource读取数据库获取更多数据源
111.
// RelaxedPropertyResolver propertyResolver = new RelaxedPropertyResolver(env,DB_DEFAULT_VALUE+".");
112.
String dsPrefixs = env.getProperty(DB_DEFAULT_VALUE + "." + DB_NAME);
113.
for (String dsPrefix : dsPrefixs.split(",")) {// 多个数据源
114.
Map<String, Object> dsMap = new HashMap<>();
115.
116.
dsMap.put("type", env.getProperty(DB_DEFAULT_VALUE + "." + dsPrefix + ".type"));
117.
dsMap.put("driver-class-name", env.getProperty(DB_DEFAULT_VALUE + "." + dsPrefix + ".driver-class-name"));
118.
dsMap.put("url", env.getProperty(DB_DEFAULT_VALUE + "." + dsPrefix + ".url"));
119.
dsMap.put("username", env.getProperty(DB_DEFAULT_VALUE + "." + dsPrefix + ".username"));
120.
dsMap.put("password", env.getProperty(DB_DEFAULT_VALUE + "." + dsPrefix + ".password"));
121.
122.
123.
DataSource ds = buildDataSource(dsMap);
124.
customDataSources.put(dsPrefix, ds);
125.
}
126.
}
127.
128.
129.
130.
@Override
131.
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
132.
Map<Object, Object> targetDataSources = new HashMap<Object, Object>();
133.
// 将主数据源添加到更多数据源中
134.
targetDataSources.put("dataSource", defaultDataSource);
135.
DynamicDataSourceContextHolder.dataSourceIds.add("dataSource");
136.
// 添加更多数据源
137.
targetDataSources.putAll(customDataSources);
138.
for (String key : customDataSources.keySet()) {
139.
DynamicDataSourceContextHolder.dataSourceIds.add(key);
140.
}
141.
142.
// 创建DynamicDataSource
143.
GenericBeanDefinition beanDefinition = new GenericBeanDefinition();
144.
beanDefinition.setBeanClass(DynamicDataSource.class);
145.
beanDefinition.setSynthetic(true);
146.
MutablePropertyValues mpv = beanDefinition.getPropertyValues();
147.
mpv.addPropertyValue("defaultTargetDataSource", defaultDataSource);
148.
mpv.addPropertyValue("targetDataSources", targetDataSources);
149.
registry.registerBeanDefinition("dataSource", beanDefinition);
150.
151.
logger.info("Dynamic DataSource Registry");
152.
}
153.
154.
// 创建DataSource
155.
@SuppressWarnings("unchecked")
156.
public DataSource buildDataSource(Map<String, Object> dsMap) {
157.
try {
158.
Object type = dsMap.get("type");
159.
if (type == null)
160.
type = DATASOURCE_TYPE_DEFAULT;// 默认DataSource
161.
162.
Class<? extends DataSource> dataSourceType;
163.
dataSourceType = (Class<? extends DataSource>) Class.forName((String) type);
164.
165.
String driverClassName = dsMap.get("driver-class-name").toString();
166.
String url = dsMap.get("url").toString();
167.
String username = dsMap.get("username").toString();
168.
String password = dsMap.get("password").toString();
169.
170.
DataSourceBuilder factory = DataSourceBuilder.create().driverClassName(driverClassName).url(url)
171.
.username(username).password(password).type(dataSourceType);
172.
return factory.build();
173.
} catch (ClassNotFoundException e) {
174.
e.printStackTrace();
175.
}
176.
return null;
177.
}
178.
}
参考文献
Spring Boot 动态数据源(多数据源自动切换)