【你好Archaius】九:Netflix Archaius的动态属性包装器-PropertyWrapper

每日一句

人生就像骑单车。想保持平衡就得往前走

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 如:DynamicIntPropertyDynamicStringPropertyDynamicBooleanProperty等。因为不需要回调的就不注册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缓存了具体类型的值 如booleanValuecachedStringValueintegerValuelongValuefloatValuedoubleValueclassValue
注意DynamicProperty中的缓存是避免了多次将字符串转换成 这些类型的开销。而我们现在说的这个缓存 缓存的是一个int/long/boolean/double/float类型的值 不需要拆箱 所以节省了拆箱的时间,拿空间换时间。既然是节省拆箱的时间 那DynamicStringProperty肯定不会有对应的CachedDynamicIntProperty

所以总结以下的两点:

  • DynamicProperty: 中的CacheValue 避免了重复的将字符串转成具体类型的时间消耗
  • CachedDynamicXXXProperty:中的缓存 避免了拆箱的时间消耗

总结

关于动态属性包装器PropertyWrapper 我们就到这。主要的逻辑还是在PropertyWrapper的构造方法中,至于PropertyWrapper衍生出来的一些类比较简单 就不再一一贴源码了。

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值