因?yàn)橛辛薬uto-configure , 我們?cè)?SpringBoot 的 配置得到了極大的簡(jiǎn)化 , 比如數(shù)據(jù)源 , 我們只需要在 application.properties 中進(jìn)行聲明相關(guān)的參數(shù)就可以 , 但有一些場(chǎng)景 , 我們需要加載多個(gè)數(shù)據(jù)源 , 這里簡(jiǎn)單介紹一下多數(shù)據(jù)源的配置
創(chuàng)建數(shù)據(jù)源配置
@Configuration
@PropertySource(encoding = "utf-8" , value = "file:/fileName.properties")
public class JobDataSourceConfiguration {
// 標(biāo)記為主數(shù)據(jù)源
@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=
如何使用
在上面 , 我們配置了三個(gè)數(shù)據(jù)源 , 并且標(biāo)記了tradeDataSource為默認(rèn)數(shù)據(jù)源
如果我們程序中 , 有使用Jpa 和 autoconfigure的話 , 那么默認(rèn)的數(shù)據(jù)源 會(huì)自己注入 .
如果使用 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 是如何幫助我們創(chuàng)建數(shù)據(jù)源的 ?
通過(guò)上面的方式 , 我們已經(jīng)可以創(chuàng)建多個(gè)數(shù)據(jù)源并開(kāi)始使用了
但可能有些同學(xué) 還比較好奇 DataSourceBuilder究竟做了什么
下面我們分析一下它的源碼
public class DataSourceBuilder {
// 支持的數(shù)據(jù)源池
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<String, String> properties = new HashMap();
// 1. 實(shí)例化
public static DataSourceBuilder create() {
return new DataSourceBuilder((ClassLoader)null);
}
// 1. 實(shí)例化 , 并且傳入ClassLoader
public static DataSourceBuilder create(ClassLoader classLoader) {
return new DataSourceBuilder(classLoader);
}
public DataSourceBuilder(ClassLoader classLoader) {
this.classLoader = classLoader;
}
// 2. 創(chuàng)建數(shù)據(jù)源
public DataSource build() {
// 3. 獲取數(shù)據(jù)源類型
Class<? extends DataSource> type = this.getType();
// 5. 實(shí)例化數(shù)據(jù)源
DataSource result = (DataSource)BeanUtils.instantiate(type);
// 6. 嘗試獲取驅(qū)動(dòng)類名
this.maybeGetDriverClassName();
// 7. 在數(shù)據(jù)源中 , 綁定配置中的參數(shù)
this.bind(result);
return result;
}
private void maybeGetDriverClassName() {
// 如果實(shí)例中沒(méi)有直接聲明驅(qū)動(dòng)類 , 并且實(shí)例中聲明了數(shù)據(jù)庫(kù)連接的地址
if(!this.properties.containsKey("driverClassName") && this.properties.containsKey("url")) {
String url = (String)this.properties.get("url");
// 根據(jù) 連接地址 解析驅(qū)動(dòng)類名
String driverClass = DatabaseDriver.fromJdbcUrl(url).getDriverClassName();
this.properties.put("driverClassName", driverClass);
}
}
// 在數(shù)據(jù)源中 , 綁定配置中的參數(shù)
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;
}
// 顯示的傳入 驅(qū)動(dòng)類名
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. 查找數(shù)據(jù)源的具體類型
public Class<? extends DataSource> findType() {
// 如果實(shí)例中, 已經(jīng)存在數(shù)據(jù)源類型了 , 那么直接返回
if(this.type != null) {
return this.type;
} else {
String[] var1 = DATA_SOURCE_TYPE_NAMES;
int var2 = var1.length;
int var3 = 0;
// 支持的數(shù)據(jù)源類型
while(var3 < var2) {
String name = var1[var3];
// 查找數(shù)據(jù)源的類 , 如果在查找不到的話 , 移動(dòng)下標(biāo), 查找下一個(gè)數(shù)據(jù)源
try {
return ClassUtils.forName(name, this.classLoader);
} catch (Exception var6) {
++var3;
}
}
return null;
}
}
// 3. 獲取數(shù)據(jù)源類型
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");
}
}
}