因为有了auto-configure , 我们在 SpringBoot 的 配置得到了极大的简化 , 比如数据源 , 我们只需要在 application.properties 中进行声明相关的参数就可以 , 但有一些场景 , 我们需要加载多个数据源 , 这里简单介绍一下多数据源的配置
创建数据源配置
@Configuration
@PropertySource(encoding = "utf-8" , value = "file:/fileName.properties")
public class JobDataSourceConfiguration {
// 标记为主数据源
@Primary
@Bean("tradeDataSource")
@ConfigurationProperties(value = "datasource.trade")
public DataSource tradeDataSource(){
return DataSourceBuilder.create().build();
}
@Bean("paymentDataSource")
@ConfigurationProperties(value = "datasource.payment")
public DataSource paymentDataSource(){
return DataSourceBuilder.create().build();
}
@Bean("productDataSource")
@ConfigurationProperties(value = "datasource.product")
public DataSource productDataSource(){
return DataSourceBuilder.create().build();
}
}
配置文件
#trade
datasource.trade.jdbc-url=
datasource.trade.username=
datasource.trade.password=
datasource.trade.driver-class-name=com.mysql.jdbc.Driver
datasource.trade.type=com.zaxxer.hikari.HikariDataSource
datasource.trade.hikari.maximum-pool-size=
datasource.trade.hikari.minimum-idle=
datasource.trade.hikari.idle-timeout=
#info
datasource.product.jdbc-url=
datasource.product.username=
datasource.product.password=
datasource.product.driver-class-name=com.mysql.jdbc.Driver
datasource.product.type=com.zaxxer.hikari.HikariDataSource
datasource.product.hikari.maximum-pool-size=
datasource.product.hikari.minimum-idle=
datasource.product.hikari.idle-timeout=
#payment
datasource.payment.jdbc-url=
datasource.payment.username=
datasource.payment.password=
datasource.payment.driver-class-name=com.mysql.jdbc.Driver
datasource.payment.type=com.zaxxer.hikari.HikariDataSource
datasource.payment.hikari.maximum-pool-size=
datasource.payment.hikari.minimum-idle=
datasource.payment.hikari.idle-timeout=
如何使用
在上面 , 我们配置了三个数据源 , 并且标记了tradeDataSource为默认数据源
如果我们程序中 , 有使用Jpa 和 autoconfigure的话 , 那么默认的数据源 会自己注入 .
如果使用 JdbcTemplate 可参考下述方式
@Configuration
public class JdbcTemplateConfiguration {
@Bean("tradeJdbcTemplate")
public JdbcTemplate tradeJdbcTemplate(@Qualifier("tradeDataSource") DataSource dataSource){
return new JdbcTemplate(dataSource);
}
@Bean("productJdbcTemplate")
public JdbcTemplate productJdbcTemplate(@Qualifier("productDataSource") DataSource dataSource){
return new JdbcTemplate(dataSource);
}
@Bean("paymentJdbcTemplate")
public JdbcTemplate paymentJdbcTemplate(@Qualifier("paymentDataSource") DataSource dataSource){
return new JdbcTemplate(dataSource);
}
}
DataSourceBuilder 是如何帮助我们创建数据源的 ?
通过上面的方式 , 我们已经可以创建多个数据源并开始使用了
但可能有些同学 还比较好奇 DataSourceBuilder究竟做了什么
下面我们分析一下它的源码
public class DataSourceBuilder {
// 支持的数据源池
private static final String[] DATA_SOURCE_TYPE_NAMES = new String[]{"org.apache.tomcat.jdbc.pool.DataSource", "com.zaxxer.hikari.HikariDataSource", "org.apache.commons.dbcp.BasicDataSource", "org.apache.commons.dbcp2.BasicDataSource"};
private Class extends DataSource> type;
private ClassLoader classLoader;
private Map properties = new HashMap();
// 1. 实例化
public static DataSourceBuilder create() {
return new DataSourceBuilder((ClassLoader)null);
}
// 1. 实例化 , 并且传入ClassLoader
public static DataSourceBuilder create(ClassLoader classLoader) {
return new DataSourceBuilder(classLoader);
}
public DataSourceBuilder(ClassLoader classLoader) {
this.classLoader = classLoader;
}
// 2. 创建数据源
public DataSource build() {
// 3. 获取数据源类型
Class extends DataSource> type = this.getType();
// 5. 实例化数据源
DataSource result = (DataSource)BeanUtils.instantiate(type);
// 6. 尝试获取驱动类名
this.maybeGetDriverClassName();
// 7. 在数据源中 , 绑定配置中的参数
this.bind(result);
return result;
}
private void maybeGetDriverClassName() {
// 如果实例中没有直接声明驱动类 , 并且实例中声明了数据库连接的地址
if(!this.properties.containsKey("driverClassName") && this.properties.containsKey("url")) {
String url = (String)this.properties.get("url");
// 根据 连接地址 解析驱动类名
String driverClass = DatabaseDriver.fromJdbcUrl(url).getDriverClassName();
this.properties.put("driverClassName", driverClass);
}
}
// 在数据源中 , 绑定配置中的参数
private void bind(DataSource result) {
MutablePropertyValues properties = new MutablePropertyValues(this.properties);
(new RelaxedDataBinder(result)).withAlias("url", new String[]{"jdbcUrl"}).withAlias("username", new String[]{"user"}).bind(properties);
}
// 显示的传入 url
public DataSourceBuilder type(Class extends DataSource> type) {
this.type = type;
return this;
}
// 显示的传入 url
public DataSourceBuilder url(String url) {
this.properties.put("url", url);
return this;
}
// 显示的传入 驱动类名
public DataSourceBuilder driverClassName(String driverClassName) {
this.properties.put("driverClassName", driverClassName);
return this;
}
// 显示的传入 用户名
public DataSourceBuilder username(String username) {
this.properties.put("username", username);
return this;
}
// 显示的传入 密码
public DataSourceBuilder password(String password) {
this.properties.put("password", password);
return this;
}
// 4. 查找数据源的具体类型
public Class extends DataSource> findType() {
// 如果实例中, 已经存在数据源类型了 , 那么直接返回
if(this.type != null) {
return this.type;
} else {
String[] var1 = DATA_SOURCE_TYPE_NAMES;
int var2 = var1.length;
int var3 = 0;
// 支持的数据源类型
while(var3 < var2) {
String name = var1[var3];
// 查找数据源的类 , 如果在查找不到的话 , 移动下标, 查找下一个数据源
try {
return ClassUtils.forName(name, this.classLoader);
} catch (Exception var6) {
++var3;
}
}
return null;
}
}
// 3. 获取数据源类型
private Class extends DataSource> getType() {
Class extends DataSource> type = this.findType();
if(type != null) {
return type;
} else {
throw new IllegalStateException("No supported DataSource type found");
}
}
}