فهرست منبع

优化链接无法读取数据

callm 2 روز پیش
والد
کامیت
1474a5a327
2فایلهای تغییر یافته به همراه57 افزوده شده و 20 حذف شده
  1. 41 19
      src/main/java/com/uas/eis/core/config/DynamicDataSourceRegister.java
  2. 16 1
      src/main/resources/application.yml

+ 41 - 19
src/main/java/com/uas/eis/core/config/DynamicDataSourceRegister.java

@@ -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));
     }
    
  

+ 16 - 1
src/main/resources/application.yml

@@ -5,6 +5,22 @@ spring:
         username: N_MES_ZK
         password: select!#%*(
         url: jdbc:oracle:thin:@127.0.0.1:1521:orcl
+        # ---- 连接池参数(会被 DynamicDataSourceRegister.dataBinder 绑定到池上) ----
+        # 空闲连接保活/校验:不配的话空闲连接被防火墙或Oracle静默断开后无人知晓,
+        # 回收线程关闭时才报"close connection error / 无法从套接字读取更多的数据"
+        validationQuery: SELECT 1 FROM DUAL
+        testWhileIdle: true
+        testOnBorrow: true
+        minIdle: 1
+        maxActive: 50
+        initialSize: 5
+        maxWait: 10000
+        timeBetweenEvictionRunsMillis: 60000
+        # 空闲超过5分钟即回收,必须小于防火墙/NAT的空闲断开时间,避免留着一堆死连接
+        minEvictableIdleTimeMillis: 300000
+        # 借出连接超过10分钟未归还则强制回收,防止业务异常导致连接泄漏
+        removeAbandoned: true
+        removeAbandonedTimeout: 600
     http:
         encoding:
             force: true
@@ -20,7 +36,6 @@ server:
         uri_encoding: UTF-8
     context-path:
         /EIS
-
 logging:
   level:
     org: