前言
这里是继上文中,关于数据源配置了下划线之后读取不到的问题的探究。再上篇文章中我在文章里强调了这个问题,网上说的模棱两可。官方文档也未作出详细说明,所以自己花了点时间,进行调试略有心得,在这里分享!
前文
《Sharding-JDBC简单使用》
《Sharding-JDBC主子表(绑定表)关联》
《Sharding-JDBC读写分离配置》
故障重现
我在配置文件里,给数据源名称设置了下划线,然后报错
根据代码调试原则,哪里能点点哪里。
调试之旅
我们看这里,是放置数据源的地方org.apache.shardingsphere.shardingjdbc.spring.boot.SpringBootConfiguration.setEnvironment
Map<String, Object> dataSourceProps = (Map)PropertyUtil.handle(environment, prefix + dataSourceName.trim(), Map.class);
这行代码往下就报错,说明问题就是从这里抛出来的进去!!!
调试代码就是要一点点重来一点点进(谁让我菜,我只能这样,你要是有走读代码的能力,自然更好!)
springboot1.x走v1,springboot2.x走v2,这里并不是重点
@SneakyThrows
private static Object v2(final Environment environment, final String prefix, final Class<?> targetClass) {
Class<?> binderClass = Class.forName("org.springframework.boot.context.properties.bind.Binder");
Method getMethod = binderClass.getDeclaredMethod("get", Environment.class);
Method bindMethod = binderClass.getDeclaredMethod("bind", String.class, Class.class);
Object binderObject = getMethod.invoke(null, environment);
String prefixParam = prefix.endsWith(".") ? prefix.substring(0, prefix.length() - 1) : prefix;
//这里是关键,你看他究竟反射调用哪个方法!
Object bindResultObject = bindMethod.invoke(binderObject, prefixParam, targetClass);
Method resultGetMethod = bindResultObject.getClass().getDeclaredMethod("get");
return resultGetMethod.invoke(bindResultObject);
}
他这里反射调用了binder
binder里的bind方法有很多重载,不过都不重要,因为他根本进行不下去,说明在进去的那个方法就报错所以说细看
this.bind((ConfigurationPropertyName)ConfigurationPropertyName.of(name), target, (BindHandler)null);
进入ConfigurationPropertyName.of(name)
一路进入到这里
直接看这里
Elements elements = (new ElementsParser(name, ‘.’, parserCapacity)).parse();
for(int i = 0; i < length; ++i) {
char ch = this.source.charAt(i);
if (ch == '[') {
if (openBracketCount == 0) {
this.add(start, i, type, valueProcessor);
start = i + 1;
type = ConfigurationPropertyName.ElementType.NUMERICALLY_INDEXED;
}
++openBracketCount;
} else if (ch == ']') {
--openBracketCount;
if (openBracketCount == 0) {
this.add(start, i, type, valueProcessor);
start = i + 1;
type = ConfigurationPropertyName.ElementType.EMPTY;
}
} else if (!type.isIndexed() && ch == this.separator) {
this.add(start, i, type, valueProcessor);
start = i + 1;
type = ConfigurationPropertyName.ElementType.EMPTY;
} else {
type = this.updateType(type, ch, i - start);
}
}
直接把遍历的下标条件设置成35,方便自己一直调试
https://blog.csdn.net/weixin_43953546/article/details/102807792 左击打断点,右击输入条件
这里我们能看到他是在遍历spring.shardingsphere.datasource.ds0_master
这个字符串,到这里我们大概能猜到了,可能是这个_
, 这里属于非法字符串(猜对了)
断点进入到isValidChar
这个方法!
其实到这里,看名字我们都能猜到并证实自己猜想了
必须是a-z 或则 0-9或者-,其余都是非法字符串!!
反证
取消下划线,使用大写M,执行,果然报错!