mirror of
https://gitee.com/mybatis-flex/mybatis-flex.git
synced 2025-12-08 01:28:24 +08:00
add multi datasource support
This commit is contained in:
parent
c1340f256b
commit
3006ab30da
@ -0,0 +1,140 @@
|
||||
/**
|
||||
* Copyright (c) 2022-2023, Mybatis-Flex (fuhai999@gmail.com).
|
||||
* <p>
|
||||
* 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
|
||||
* <p>
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* <p>
|
||||
* 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.mybatisflex.spring.boot;
|
||||
|
||||
import com.mybatisflex.core.table.ConvertUtil;
|
||||
import com.mybatisflex.core.util.StringUtil;
|
||||
import org.apache.ibatis.reflection.Reflector;
|
||||
import org.apache.ibatis.reflection.invoker.Invoker;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class DataSourceBuilder {
|
||||
|
||||
private static Map<String, String> dataSourceAlias = new HashMap<>();
|
||||
|
||||
static {
|
||||
dataSourceAlias.put("druid", "com.alibaba.druid.pool.DruidDataSource");
|
||||
dataSourceAlias.put("hikari", "com.zaxxer.hikari.HikariDataSource");
|
||||
dataSourceAlias.put("hikaricp", "com.zaxxer.hikari.HikariDataSource");
|
||||
dataSourceAlias.put("bee", "cn.beecp.BeeDataSource");
|
||||
dataSourceAlias.put("beecp", "cn.beecp.BeeDataSource");
|
||||
dataSourceAlias.put("dbcp", "org.apache.commons.dbcp2.BasicDataSource");
|
||||
dataSourceAlias.put("dbcp2", "org.apache.commons.dbcp2.BasicDataSource");
|
||||
}
|
||||
|
||||
private Map<String, String> dataSourceProperties;
|
||||
|
||||
public DataSourceBuilder(Map<String, String> dataSourceProperties) {
|
||||
this.dataSourceProperties = dataSourceProperties;
|
||||
}
|
||||
|
||||
public DataSource build() {
|
||||
String dataSourceClassName = null;
|
||||
String type = dataSourceProperties.get("type");
|
||||
if (StringUtil.isNotBlank(type)) {
|
||||
if (dataSourceAlias.containsKey(type)) {
|
||||
dataSourceClassName = dataSourceAlias.get(type);
|
||||
} else {
|
||||
dataSourceClassName = type;
|
||||
}
|
||||
} else {
|
||||
dataSourceClassName = detectDataSourceClass();
|
||||
}
|
||||
|
||||
if (StringUtil.isBlank(dataSourceClassName)) {
|
||||
throw new IllegalArgumentException("Cannot find the dataSource type: " + type);
|
||||
}
|
||||
|
||||
try {
|
||||
Class<?> dataSourceClass = Class.forName(dataSourceClassName);
|
||||
Object dataSourceObject = dataSourceClass.newInstance();
|
||||
setDataSourceProperties(dataSourceObject);
|
||||
return (DataSource) dataSourceObject;
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("Cannot new instance dataSource by class: " + dataSourceClassName);
|
||||
}
|
||||
}
|
||||
|
||||
private void setDataSourceProperties(Object dataSourceObject) throws Exception {
|
||||
Reflector reflector = new Reflector(dataSourceObject.getClass());
|
||||
for (String attr : dataSourceProperties.keySet()) {
|
||||
String value = dataSourceProperties.get(attr);
|
||||
String camelAttr = attrToCamel(attr);
|
||||
if ("url".equals(camelAttr) || "jdbcUrl".equals(camelAttr)) {
|
||||
if (reflector.hasSetter("url")) {
|
||||
reflector.getSetInvoker("url").invoke(dataSourceObject, new Object[]{value});
|
||||
} else if (reflector.hasSetter("jdbcUrl")) {
|
||||
reflector.getSetInvoker("jdbcUrl").invoke(dataSourceObject, new Object[]{value});
|
||||
}
|
||||
} else {
|
||||
if (reflector.hasSetter(camelAttr)) {
|
||||
Invoker setInvoker = reflector.getSetInvoker(camelAttr);
|
||||
setInvoker.invoke(dataSourceObject, new Object[]{ConvertUtil.convert(value, setInvoker.getType())});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static String attrToCamel(String string) {
|
||||
String temp = string.toLowerCase();
|
||||
int strLen = temp.length();
|
||||
StringBuilder sb = new StringBuilder(strLen);
|
||||
for (int i = 0; i < strLen; i++) {
|
||||
char c = temp.charAt(i);
|
||||
if (c == '-') {
|
||||
if (++i < strLen) {
|
||||
sb.append(Character.toUpperCase(temp.charAt(i)));
|
||||
}
|
||||
} else {
|
||||
sb.append(c);
|
||||
}
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
|
||||
private String detectDataSourceClass() {
|
||||
String[] detectClassNames = new String[]{
|
||||
"com.alibaba.druid.pool.DruidDataSource",
|
||||
"com.zaxxer.hikari.HikariDataSource",
|
||||
"cn.beecp.BeeDataSource",
|
||||
"org.apache.commons.dbcp2.BasicDataSource",
|
||||
};
|
||||
|
||||
for (String detectClassName : detectClassNames) {
|
||||
String result = doDetectDataSourceClass(detectClassName);
|
||||
if (result != null) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
private String doDetectDataSourceClass(String className) {
|
||||
try {
|
||||
Class.forName(className);
|
||||
return className;
|
||||
} catch (ClassNotFoundException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,70 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2022-2023, Mybatis-Flex (fuhai999@gmail.com).
|
||||
* <p>
|
||||
* 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
|
||||
* <p>
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* <p>
|
||||
* 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.mybatisflex.spring.boot;
|
||||
|
||||
/**
|
||||
* 参考 {@link org.springframework.boot.autoconfigure.jdbc.DataSourceProperties}
|
||||
* 自定义 DataSourceProperty,在未来可以提供更多的扩展
|
||||
*/
|
||||
public class DataSourceProperty {
|
||||
|
||||
private String type;
|
||||
private String driverClassName;
|
||||
private String url;
|
||||
private String username;
|
||||
private String password;
|
||||
|
||||
|
||||
public String getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public void setType(String type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public String getDriverClassName() {
|
||||
return driverClassName;
|
||||
}
|
||||
|
||||
public void setDriverClassName(String driverClassName) {
|
||||
this.driverClassName = driverClassName;
|
||||
}
|
||||
|
||||
public String getUrl() {
|
||||
return url;
|
||||
}
|
||||
|
||||
public void setUrl(String url) {
|
||||
this.url = url;
|
||||
}
|
||||
|
||||
public String getUsername() {
|
||||
return username;
|
||||
}
|
||||
|
||||
public void setUsername(String username) {
|
||||
this.username = username;
|
||||
}
|
||||
|
||||
public String getPassword() {
|
||||
return password;
|
||||
}
|
||||
|
||||
public void setPassword(String password) {
|
||||
this.password = password;
|
||||
}
|
||||
}
|
||||
@ -15,13 +15,8 @@
|
||||
*/
|
||||
package com.mybatisflex.spring.boot;
|
||||
|
||||
import cn.beecp.BeeDataSource;
|
||||
import com.alibaba.druid.pool.DruidDataSource;
|
||||
import com.mybatisflex.core.datasource.RoutingDataSource;
|
||||
import com.mybatisflex.core.util.StringUtil;
|
||||
import com.mybatisflex.spring.FlexSqlSessionFactoryBean;
|
||||
import com.zaxxer.hikari.HikariDataSource;
|
||||
import org.apache.commons.dbcp2.BasicDataSource;
|
||||
import org.apache.ibatis.mapping.DatabaseIdProvider;
|
||||
import org.apache.ibatis.plugin.Interceptor;
|
||||
import org.apache.ibatis.scripting.LanguageDriver;
|
||||
@ -31,8 +26,10 @@ import org.mybatis.spring.SqlSessionFactoryBean;
|
||||
import org.springframework.beans.BeanWrapperImpl;
|
||||
import org.springframework.beans.factory.ObjectProvider;
|
||||
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
|
||||
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
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.core.io.Resource;
|
||||
@ -42,7 +39,10 @@ import org.springframework.util.StringUtils;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
import java.beans.PropertyDescriptor;
|
||||
import java.util.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
@ -55,25 +55,13 @@ import java.util.stream.Stream;
|
||||
@ConditionalOnPropertyEmpty("spring.datasource.url")
|
||||
@EnableConfigurationProperties(MybatisFlexProperties.class)
|
||||
@AutoConfigureAfter({MybatisLanguageDriverAutoConfiguration.class})
|
||||
@AutoConfigureBefore({DataSourceAutoConfiguration.class})
|
||||
public class MultiDataSourceAutoConfiguration extends MybatisFlexAutoConfiguration {
|
||||
|
||||
private List<SqlSessionFactory> sqlSessionFactories = new ArrayList<>();
|
||||
private List<DataSource> dataSources = new ArrayList<>();
|
||||
|
||||
|
||||
private static Map<String, String> dataSourceAlias = new HashMap<>();
|
||||
|
||||
static {
|
||||
dataSourceAlias.put("druid", "com.alibaba.druid.pool.DruidDataSource");
|
||||
dataSourceAlias.put("hikari", "com.zaxxer.hikari.HikariDataSource");
|
||||
dataSourceAlias.put("hikaricp", "com.zaxxer.hikari.HikariDataSource");
|
||||
dataSourceAlias.put("bee", "cn.beecp.BeeDataSource");
|
||||
dataSourceAlias.put("beecp", "cn.beecp.BeeDataSource");
|
||||
dataSourceAlias.put("dbcp", "org.apache.commons.dbcp2.BasicDataSource");
|
||||
dataSourceAlias.put("dbcp2", "org.apache.commons.dbcp2.BasicDataSource");
|
||||
}
|
||||
|
||||
|
||||
public MultiDataSourceAutoConfiguration(MybatisFlexProperties properties
|
||||
, ObjectProvider<Interceptor[]> interceptorsProvider
|
||||
, ObjectProvider<TypeHandler[]> typeHandlersProvider
|
||||
@ -88,110 +76,14 @@ public class MultiDataSourceAutoConfiguration extends MybatisFlexAutoConfigurati
|
||||
}
|
||||
|
||||
|
||||
private void initDataSources(Map<String, DataSourceProperty> datasourceMap) {
|
||||
private void initDataSources(Map<String, Map<String, String>> datasourceMap) {
|
||||
if (datasourceMap != null) {
|
||||
datasourceMap.forEach((s, dsp) -> {
|
||||
SqlSessionFactory sqlSessionFactory = buildSqlSessionFactory(s, createDataSource(dsp));
|
||||
DataSource dataSource = new DataSourceBuilder(dsp).build();
|
||||
SqlSessionFactory sqlSessionFactory = buildSqlSessionFactory(s, dataSource);
|
||||
sqlSessionFactories.add(sqlSessionFactory);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
private DataSource createDataSource(DataSourceProperty dataSourceProperty) {
|
||||
String type = dataSourceProperty.getType();
|
||||
if (StringUtil.isBlank(type)) {
|
||||
type = detectDataSourceClass();
|
||||
}
|
||||
if (StringUtil.isBlank(type)) {
|
||||
throw new IllegalArgumentException("The dataSource cannot be null or empty.");
|
||||
}
|
||||
|
||||
switch (type) {
|
||||
case "druid":
|
||||
case "com.alibaba.druid.pool.DruidDataSource":
|
||||
return createDruidDataSource(dataSourceProperty);
|
||||
case "hikari":
|
||||
case "hikaricp":
|
||||
case "com.zaxxer.hikari.HikariDataSource":
|
||||
return createHikariDataSource(dataSourceProperty);
|
||||
case "bee":
|
||||
case "beecp":
|
||||
case "cn.beecp.BeeDataSource":
|
||||
return createBeeDataSource(dataSourceProperty);
|
||||
case "dbcp":
|
||||
case "dbcp2":
|
||||
case "org.apache.commons.dbcp2.BasicDataSource":
|
||||
return createDbcpDataSource(dataSourceProperty);
|
||||
default:
|
||||
throw new IllegalArgumentException("Cannot Support the dataSource type:" + dataSourceProperty.getType());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private String detectDataSourceClass() {
|
||||
String[] detectClassNames = new String[]{
|
||||
"com.alibaba.druid.pool.DruidDataSource",
|
||||
"com.zaxxer.hikari.HikariDataSource",
|
||||
"cn.beecp.BeeDataSource",
|
||||
"org.apache.commons.dbcp2.BasicDataSource",
|
||||
};
|
||||
|
||||
for (String detectClassName : detectClassNames) {
|
||||
String result = doDetectDataSourceClass(detectClassName);
|
||||
if (result != null) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private String doDetectDataSourceClass(String className) {
|
||||
try {
|
||||
Class.forName(className);
|
||||
return className;
|
||||
} catch (ClassNotFoundException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private DataSource createDbcpDataSource(DataSourceProperty dataSourceProperty) {
|
||||
BasicDataSource ds = new BasicDataSource();
|
||||
ds.setUrl(dataSourceProperty.getUrl());
|
||||
ds.setUsername(dataSourceProperty.getUsername());
|
||||
ds.setPassword(dataSourceProperty.getPassword());
|
||||
ds.setDriverClassName(dataSourceProperty.getDriverClassName());
|
||||
return ds;
|
||||
}
|
||||
|
||||
private DataSource createBeeDataSource(DataSourceProperty dataSourceProperty) {
|
||||
BeeDataSource ds = new BeeDataSource();
|
||||
ds.setJdbcUrl(dataSourceProperty.getUrl());
|
||||
ds.setUsername(dataSourceProperty.getUsername());
|
||||
ds.setPassword(dataSourceProperty.getPassword());
|
||||
ds.setDriverClassName(dataSourceProperty.getDriverClassName());
|
||||
return ds;
|
||||
}
|
||||
|
||||
|
||||
private DataSource createDruidDataSource(DataSourceProperty dataSourceProperty) {
|
||||
DruidDataSource ds = new DruidDataSource();
|
||||
ds.setUrl(dataSourceProperty.getUrl());
|
||||
ds.setUsername(dataSourceProperty.getUsername());
|
||||
ds.setPassword(dataSourceProperty.getPassword());
|
||||
ds.setDriverClassName(dataSourceProperty.getDriverClassName());
|
||||
return ds;
|
||||
}
|
||||
|
||||
|
||||
private DataSource createHikariDataSource(DataSourceProperty dataSourceProperty) {
|
||||
HikariDataSource ds = new HikariDataSource();
|
||||
ds.setJdbcUrl(dataSourceProperty.getUrl());
|
||||
ds.setUsername(dataSourceProperty.getUsername());
|
||||
ds.setPassword(dataSourceProperty.getPassword());
|
||||
if (StringUtil.isNotBlank(dataSourceProperty.getDriverClassName())) {
|
||||
ds.setDriverClassName(dataSourceProperty.getDriverClassName());
|
||||
}
|
||||
return ds;
|
||||
}
|
||||
|
||||
|
||||
@ -264,14 +156,14 @@ public class MultiDataSourceAutoConfiguration extends MybatisFlexAutoConfigurati
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public SqlSessionFactory sqlSessionFactory() {
|
||||
return sqlSessionFactories.get(0);
|
||||
return sqlSessionFactories.isEmpty() ? null : sqlSessionFactories.get(0);
|
||||
}
|
||||
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public DataSource dataSource() {
|
||||
return dataSources.get(0);
|
||||
return dataSources.isEmpty() ? null : dataSources.get(0);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -48,7 +48,7 @@ public class MybatisFlexProperties {
|
||||
//多数据源的配置
|
||||
//mybatis-flex.datasource.ds1.url=***
|
||||
//mybatis-flex.datasource.ds2.url=***
|
||||
private Map<String, DataSourceProperty> datasource;
|
||||
private Map<String, Map<String,String>> datasource;
|
||||
|
||||
/**
|
||||
* Location of MyBatis xml config file.
|
||||
@ -102,11 +102,11 @@ public class MybatisFlexProperties {
|
||||
*/
|
||||
private CoreConfiguration configuration;
|
||||
|
||||
public Map<String, DataSourceProperty> getDatasource() {
|
||||
public Map<String, Map<String, String>> getDatasource() {
|
||||
return datasource;
|
||||
}
|
||||
|
||||
public void setDatasource(Map<String, DataSourceProperty> datasource) {
|
||||
public void setDatasource(Map<String, Map<String, String>> datasource) {
|
||||
this.datasource = datasource;
|
||||
}
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user