之前排查线上问题,发现数据源的部分配置没有生效,结果跟了下源码,发现Properties这个类的新大陆,这里记录分享下
下面的代码,大家认为输出分别是多少? 我先说结果啊,size:1 ,value: CHINA
Properties firstProperty = new Properties();
firstProperty.setProperty("zone", "CHINA");
firstProperty.setProperty("time-out", "3000");
Properties secondProperty = new Properties(firstProperty);
secondProperty.setProperty("idle-num", "5");
System.out.println("size: " + secondProperty.size());
System.out.println("value: " + secondProperty.getProperty("zone"));
原因是 Properties 这个类 实际是一个HashTable,但同时呢,他内部有个属性叫做 default
/**
* A property list that contains default values for any keys not
* found in this property list.
*
* @serial
*/
protected Properties defaults;
我们使用构造函数声明 Properties 时,其实只是初始化了他的default,并没有增加 hashTable.table 的值;hashTable.table的值是通过 setProperty() 函数添加的
所以上面的代码,SIZE=1,但是拥有default值一共2个,zone:CHINA,time-out:3000
我们有些业务代码(包括某些框架,例如我这次的线上问题,com.zaxxer.hikari.HikariConfig#setDataSourceProperties) ,是通过遍历 hashTable的键值对来操作的
这里就坑爹了,会把default值遍历不到,因为default是 Properties 的属性,并不是 hashTable的
我们正常的打开方式应该是这样的
Enumeration<?> enumeration = thirdProperty.propertyNames();
while (enumeration.hasMoreElements()) {
System.out.println(enumeration.nextElement());
}
// 因为 Properties 内部有 enumerate() 这个函数,在递归
private synchronized void enumerate(Hashtable<String,Object> h) {
if (defaults != null) {
defaults.enumerate(h);
}
for (Enumeration<?> e = keys() ; e.hasMoreElements() ;) {
String key = (String)e.nextElement();
h.put(key, get(key));
}
}