公司的配置中心使用的是携程的Apollo配置中心,现在基本上所有的配置文件都迁移到了Apollo里面。Apollo的使用非常方便,实时生效,不需要重启应用。但是有个缺点,就是对配置没有进行校验,如果配置格式或者类型有问题的话,就会抛异常。
鉴于此,一些逻辑上的校验就得自己做。例如对下载的账单要进行分割,这个大小不能小于1MB。我在配置的set方法里面做了一点简单的校验,例如账单分割单位billCutSize,如果小于1MB,就直接设置为1MB。
@Value("${bill_cut_size:1}")
private int billCutSize;
public void setBillCutSize(int size){
if(size < 1){
billCutSize = 1;
}else{
billCutSize = size;
}
}
但是运行的时候,发现billCutSize设置为0的时候,并没有被替换成1,仍然是0。看来Apollo加载配置的时候,并不是通过setter方法加载的。下面通过源码进行分析说明
// apollo配置个更新后,会通过AutoUpdateConfigChangeListener触发onChange
public void onChange(ConfigChangeEvent changeEvent) {
// 获取到所有更改了的Key集合
Set<String> keys = changeEvent.changedKeys();
if(!CollectionUtils.isEmpty(keys)) {
Iterator var3 = keys.iterator();
while(true) {
String key;
Collection targetValues;
do {
do {
do {
if(!var3.hasNext()) {
return;
}
key = (String)var3.next();
targetValues = this.springValueRegistry.get(key);
} while(targetValues == null);
} while(targetValues.isEmpty());
} while(!this.shouldTriggerAutoUpdate(changeEvent, key));
Iterator var6 = targetValues.iterator();
while(var6.hasNext()) {
SpringValue val = (SpringValue)var6.next();
this.updateSpringValue(val); // 就是这个方法去更新值
}
}
}
}
然后updateSpringValue里面做什么了呢?
private void updateSpringValue(SpringValue springValue) {
try {
// 解析值
Object value = this.resolvePropertyValue(springValue);
springValue.update(value); // 更新
logger.info("Auto update apollo changed value successfully, new value: {}, {}", value, springValue);
} catch (Throwable var3) {
logger.error("Auto update apollo changed value failed, {}", springValue.toString(), var3);
}
}
public void update(Object newVal) throws IllegalAccessException, InvocationTargetException {
if(this.isField()) { // 配置的值是field类型
this.injectField(newVal);
} else {
this.injectMethod(newVal);
}
}
private void injectField(Object newVal) throws IllegalAccessException {
boolean accessible = this.field.isAccessible();
this.field.setAccessible(true);
this.field.set(this.bean, newVal); // 通过反射赋值
this.field.setAccessible(accessible);
}
看到了这里就豁然开朗了,原来是通过反射对字段赋值,怪不得set方法不起作用。其实回过头来想,用spring开发久了,依赖注入的思想根深蒂固,以为什么都是靠构造器和setter进行注入。我们的configBean,其实不一定有带参数的构造器和setter方法的,这样一来通过反射进行赋值确实是更好的方法。