每日一句
人生就像骑单车。想保持平衡就得往前走
目录
DynamicPropertyFactory. getStringProperty
在前一篇文章我们分析了DynamicPropertyFactory.getInstance()
的流程,以及DynamicProperty主要的一些方法代码。提了一下DynamicProperty
是在PropertyWrapper
中创建的 这一篇文章将对PropertyWrapper
做一个介绍。
回到上一篇文章的例子中:
DynamicPropertyFactory instance = DynamicPropertyFactory.getInstance();
DynamicStringProperty stringProperty = instance.getStringProperty("con1", "defalut");
stringProperty.addCallback(() -> System.out.println("con1 属性值发生变化!"));
while (true){
System.out.println(stringProperty.get());
TimeUnit.SECONDS.sleep(10);
}
DynamicPropertyFactory instance = DynamicPropertyFactory.getInstance();
这一行代码我们已分析过了,下面来看一下instance.getStringProperty(“con1”, “defalut”);
做了什么事情。
public DynamicStringProperty getStringProperty(String propName, String defaultValue) {
return getStringProperty(propName, defaultValue, null);
}
public DynamicStringProperty getStringProperty(String propName, String defaultValue, final Runnable propertyChangeCallback) {
checkAndWarn(propName);
//这里实例化一个DynamicStringProperty
DynamicStringProperty property = new DynamicStringProperty(propName, defaultValue);
//增加一个属性变化回调函数 这里是null
addCallback(propertyChangeCallback, property);
return property;
}
上面getStringProperty
方法中 new DynamicStringProperty(propName, defaultValue);
是主要的逻辑。进入DynamicStringProperty
的构造方法:
DynamicStringProperty
本身没有做任何事情 而是调用父类的构造方法。它的父类就是 PropertyWrapper
PropertyWrapper
//持有一个DynamicProperty引用 DynamicProperty我们上一篇文章已经介绍过。
protected final DynamicProperty prop;
//保存一份默认值
protected final V defaultValue;
//不需要回调的子类
private static final IdentityHashMap<Class<? extends PropertyWrapper>, Object> SUBCLASSES_WITH_NO_CALLBACK
= new IdentityHashMap<Class<? extends PropertyWrapper>, Object>();
//存储一份回调列表 这里的回调列表和DynamicProperty中的回调列表是一致的
//这里存储一份只是为了 能够方便的通过PropertyWrapper操作callback 从而去屏蔽 DynamicProperty
private final List<Runnable> callbackList = Lists.newArrayList();
//若你有自定义的子类的实现,也可通过此方法(registerSubClassWithNoCallback)注册进来
static {
PropertyWrapper.registerSubClassWithNoCallback(DynamicIntProperty.class);
PropertyWrapper.registerSubClassWithNoCallback(DynamicStringProperty.class);
PropertyWrapper.registerSubClassWithNoCallback(DynamicBooleanProperty.class);
PropertyWrapper.registerSubClassWithNoCallback(DynamicFloatProperty.class);
PropertyWrapper.registerSubClassWithNoCallback(DynamicLongProperty.class);
PropertyWrapper.registerSubClassWithNoCallback(DynamicDoubleProperty.class);
}
protected PropertyWrapper(String propName, V defaultValue) {
//下面这行代码很重要 这里就是我们实例化DynamicProperty的地方 实例化完之后 放入DynamicProperty的ALL_PROPS缓存中
this.prop = DynamicProperty.getInstance(propName);
this.defaultValue = defaultValue;
Class<?> c = getClass();
//这里为什么会有这样一个判断?如果当前类没有被注册到 SUBCLASSES_WITH_NO_CALLBACK 就 向DynamicProperty注册回调
//这里有点不好理解。 PropertyWrapper中的propertyChanged()和validate()是空实现
//archaius的考虑是 如果把空实现注册到callbackList中 会出现性能上的不必要
//但是又不能都不注册 如果有一个类实现了 PropertyWrapper 并且实现了propertyChanged和validate
//那么如果不注册 就会导致逻辑上的错误 propertyChanged和validate不会执行
if (!SUBCLASSES_WITH_NO_CALLBACK.containsKey(c)) {
Runnable callback = new Runnable() {
public void run() {
propertyChanged();
}
};
this.prop.addCallback(callback);
//callbackList存储的callback 就是DynamicProperty中的callback的引用
//所以可以直接操作DynamicStringProperty 中的callback 这样做得目的就是隐藏DynamicProperty的细节
callbackList.add(callback);
this.prop.addValidator(new PropertyChangeValidator() {
@Override
public void validate(String newValue) {
PropertyWrapper.this.validate(newValue);
}
});
try {
if (this.prop.getString() != null) {
this.validate(this.prop.getString());
}
} catch (ValidationException e) {
logger.warn("Error validating property at initialization. Will fallback to default value.", e);
prop.updateValue(defaultValue);
}
}
}
上面代码有一个地方需要注意 if(!SUBCLASSES_WITH_NO_CALLBACK.containsKey©)
SUBCLASSES_WITH_NO_CALLBACK
这个集合存储的是不需要回调的PropertyWrapper
如:DynamicIntProperty
,DynamicStringProperty
,DynamicBooleanProperty
等。因为不需要回调的就不注册callback 所以不需要把一个空实现的callback 注册进DynamicProperty
,这样对性能造成影响,因为存储callback的是CopyOnWriteArraySet
。- 但是如果都不注册callback 那么假如有一个类实现了
PropertyWrapper
并且重写了propertyChanged
方法 那么子类的propertyChanged
方法就不会执行,这样就会造成逻辑有问题。 - 如果我们需要扩展
PropertyWrapper
并且不需要实现propertyChanged
方法 那么我们就可以通过PropertyWrapper.registerSubClassWithNoCallback
把其注册进来,当然你也可以选择不注册,也不会出现问题。注册进来性能更极致!相反如果重写了propertyChanged
那注册进去就是错误的
DynamicStringProperty
public class DynamicStringProperty extends PropertyWrapper<String> {
public DynamicStringProperty(String propName, String defaultValue) {
super(propName, defaultValue);
}
public String get() {
return prop.getString(defaultValue);
}
@Override
public String getValue() {
return get();
}
}
代码很简单 主要的逻辑都在父类实现的。可以看到该类没有复写propertyChanged()
方法 所以我们看到 DynamicStringProperty
被注册到SUBCLASSES_WITH_NO_CALLBACK
中了。
CachedDynamicIntProperty
从名字可以看出 是DynamicIntProperty
的子类,可以在更改原始值得时候缓存原始值。
看过前面讲解DynamicProperty文章的 同学可能会有疑问了,之前说DynamicProperty
缓存了具体类型的值 如booleanValue
,cachedStringValue
,integerValue
,longValue
,floatValue
,doubleValue
,classValue
。
注意DynamicProperty中的缓存是避免了多次将字符串转换成 这些类型的开销。而我们现在说的这个缓存 缓存的是一个int/long/boolean/double/float类型的值 不需要拆箱 所以节省了拆箱的时间,拿空间换时间。既然是节省拆箱的时间 那DynamicStringProperty
肯定不会有对应的CachedDynamicIntProperty
。
所以总结以下的两点:
DynamicProperty
: 中的CacheValue 避免了重复的将字符串转成具体类型的时间消耗CachedDynamicXXXProperty
:中的缓存 避免了拆箱的时间消耗
总结
关于动态属性包装器PropertyWrapper
我们就到这。主要的逻辑还是在PropertyWrapper
的构造方法中,至于PropertyWrapper
衍生出来的一些类比较简单 就不再一一贴源码了。