|
|
@@ -14,7 +14,6 @@ import javax.sql.DataSource;
|
|
|
|
|
|
|
|
|
import org.springframework.beans.MutablePropertyValues;
|
|
|
-import org.springframework.beans.PropertyValues;
|
|
|
import org.springframework.beans.factory.annotation.Autowired;
|
|
|
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
|
|
|
import org.springframework.beans.factory.support.GenericBeanDefinition;
|
|
|
@@ -40,7 +39,6 @@ public class DynamicDataSourceRegister implements ImportBeanDefinitionRegistrar
|
|
|
//如配置文件中未指定数据源类型,使用该默认值
|
|
|
private static final Object DATASOURCE_TYPE_DEFAULT = "com.alibaba.druid.pool.DruidDataSource";
|
|
|
private ConversionService conversionService = new DefaultConversionService();
|
|
|
- private PropertyValues dataSourcePropertyValues;
|
|
|
|
|
|
// 默认数据源
|
|
|
private DataSource defaultDataSource;
|
|
|
@@ -112,13 +110,11 @@ public class DynamicDataSourceRegister implements ImportBeanDefinitionRegistrar
|
|
|
@SuppressWarnings("unchecked")
|
|
|
public DataSource buildDataSource(Map<String, Object> dsMap) {
|
|
|
Object type = dsMap.get("type");
|
|
|
- if (type == null){
|
|
|
+ if (type == null || "".equals(type)){
|
|
|
type = DATASOURCE_TYPE_DEFAULT;// 默认DataSource
|
|
|
}
|
|
|
- Class<? extends DataSource> dataSourceType;
|
|
|
-
|
|
|
try {
|
|
|
- dataSourceType = (Class<? extends DataSource>) Class.forName((String) type);
|
|
|
+ Class<? extends DataSource> dataSourceType = (Class<? extends DataSource>) Class.forName((String) type);
|
|
|
String driverClassName = dsMap.get("driverClassName").toString();
|
|
|
String url = dsMap.get("url").toString();
|
|
|
String username = dsMap.get("username").toString();
|
|
|
@@ -126,29 +122,55 @@ public class DynamicDataSourceRegister implements ImportBeanDefinitionRegistrar
|
|
|
DataSourceBuilder factory = DataSourceBuilder.create().driverClassName(driverClassName).url(url).username(username).password(password).type(dataSourceType);
|
|
|
return factory.build();
|
|
|
} catch (ClassNotFoundException e) {
|
|
|
- e.printStackTrace();
|
|
|
+ //配置的连接池实现类在classpath里找不到(如配了Druid但未引入依赖),
|
|
|
+ //原来只打印堆栈并返回null,后续绑定属性时才抛"Target object must not be null",看不出真实原因
|
|
|
+ throw new RuntimeException("连接池实现类未找到: " + type + ",请检查spring.datasource.type配置与对应依赖是否已引入", e);
|
|
|
}
|
|
|
- return null;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * 为DataSource绑定更多数据
|
|
|
- * @param dataSource
|
|
|
- * @param env
|
|
|
+ * 为DataSource绑定更多数据(连接池参数)
|
|
|
+ * <p>
|
|
|
+ * 原实现只 new 了一个空的 MutablePropertyValues,从来没有把配置里的池参数放进去,导致
|
|
|
+ * application.yml 中配置的连接池参数(validationQuery、keepAlive、maxActive、各类超时等)
|
|
|
+ * 全部不生效,连接池只能跑默认值。默认没有任何空闲保活和借出校验,空闲连接被防火墙/Oracle
|
|
|
+ * 静默断开后无人知晓,直到后台回收线程 shrink 关闭时才暴露,日志里就会周期性刷
|
|
|
+ * "严重: close connection error / 无法从套接字读取更多的数据"。
|
|
|
+ * 这里改为把 spring.datasource.* 中除五要素以外的参数全部绑进池。
|
|
|
+ *
|
|
|
+ * @param dataSource 数据源(连接池)
|
|
|
+ * @param env 环境配置
|
|
|
*/
|
|
|
private void dataBinder(DataSource dataSource, Environment env){
|
|
|
+ if(dataSource == null){
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ RelaxedPropertyResolver propertyResolver = new RelaxedPropertyResolver(env, "spring.datasource.");
|
|
|
+ //五要素已通过 DataSourceBuilder 设置,不重复绑定
|
|
|
+ String[] excludes = new String[]{"type", "driverClassName", "url", "username", "password"};
|
|
|
+ Map<String, Object> values = new HashMap<String, Object>();
|
|
|
+ for(Map.Entry<String, Object> entry : propertyResolver.getSubProperties("").entrySet()){
|
|
|
+ String key = entry.getKey();
|
|
|
+ boolean exclude = false;
|
|
|
+ for(String ex : excludes){
|
|
|
+ if(ex.equalsIgnoreCase(key)){
|
|
|
+ exclude = true;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if(!exclude){
|
|
|
+ values.put(key, entry.getValue());
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if(values.isEmpty()){
|
|
|
+ return;
|
|
|
+ }
|
|
|
RelaxedDataBinder dataBinder = new RelaxedDataBinder(dataSource);
|
|
|
dataBinder.setConversionService(conversionService);
|
|
|
dataBinder.setIgnoreNestedProperties(false);//false
|
|
|
- dataBinder.setIgnoreInvalidFields(false);//false
|
|
|
+ dataBinder.setIgnoreInvalidFields(true);//池与池之间参数名不完全一致,不认识的参数忽略即可
|
|
|
dataBinder.setIgnoreUnknownFields(true);//true
|
|
|
-
|
|
|
- if(dataSourcePropertyValues == null){
|
|
|
- Map<String, Object> values = new HashMap<>();
|
|
|
- dataSourcePropertyValues = new MutablePropertyValues(values);
|
|
|
- }
|
|
|
- dataBinder.bind(dataSourcePropertyValues);
|
|
|
-
|
|
|
+ dataBinder.bind(new MutablePropertyValues(values));
|
|
|
}
|
|
|
|
|
|
|