欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

dubbo 配置中心源码分析(一)

程序员文章站 2022-03-19 14:27:49
...
Configuration 接口分析

/**
* 配置中心接口,
*/
public interface Configuration {
    /**
     * 根据给定的 key 返回对应的值.
     *
     * @param key The configuration key.
     * @return The associated string.
     */
    default String getString(String key) {
        return convert(String.class, key, null);
    }

    /**
     * 返回 key 对应的值. 如果找不到,则返回默认值.
     *
     * @param key          The configuration key.
     * @param defaultValue The default value.
     * @return The associated string if key is found and has valid
     * format, default value otherwise.
     */
    default String getString(String key, String defaultValue) {
        return convert(String.class, key, defaultValue);
    }

    /**
     * 从配置中心返回对应的值. 这是检索属性值的基本方法. 在 Configuration 接口的典型实现中,
     * 其他 get 方法(即返回特定的数据类型) 将在内部使用此方法.
     *
     * @param key property to retrieve
     * @return the value to which this configuration maps the specified key, or
     * null if the configuration contains no mapping for this key.
     */
    default Object getProperty(String key) {
        return getProperty(key, null);
    }

    /**
     * 从配置中心返回对应的 value 值. 如果配置中心不包含此 key 对应的 value,则返回默认值.
     *
     * @param key property to retrieve
     * @param defaultValue default value
     * @return the value to which this configuration maps the specified key, or default value if the configuration
     * contains no mapping for this key.
     */
    default Object getProperty(String key, Object defaultValue) {
        Object value = getInternalProperty(key);
        return value != null ? value : defaultValue;
    }

    // 待子类实现
    Object getInternalProperty(String key);

    /**
     * 检查配置中心是否包含给定的 key.
     *
     * @param key the key whose presence in this configuration is to be tested
     * @return {@code true} if the configuration contains a value for this
     * key, {@code false} otherwise
     */
    default boolean containsKey(String key) {
        return getProperty(key) != null;
    }


    // 根据给定的类型,将 key 对应的值转换为对应的类型.
    default <T> T convert(Class<T> cls, String key, T defaultValue) {
        // we only process String properties for now
        String value = (String) getProperty(key);

        if (value == null) {
            return defaultValue;
        }

        Object obj = value;
        if (cls.isInstance(value)) {
            return cls.cast(value);
        }

        if (Boolean.class.equals(cls) || Boolean.TYPE.equals(cls)) {
            obj = Boolean.valueOf(value);
        } else if (Number.class.isAssignableFrom(cls) || cls.isPrimitive()) {
            if (Integer.class.equals(cls) || Integer.TYPE.equals(cls)) {
                obj = Integer.valueOf(value);
            } else if (Long.class.equals(cls) || Long.TYPE.equals(cls)) {
                obj = Long.valueOf(value);
            } else if (Byte.class.equals(cls) || Byte.TYPE.equals(cls)) {
                obj = Byte.valueOf(value);
            } else if (Short.class.equals(cls) || Short.TYPE.equals(cls)) {
                obj = Short.valueOf(value);
            } else if (Float.class.equals(cls) || Float.TYPE.equals(cls)) {
                obj = Float.valueOf(value);
            } else if (Double.class.equals(cls) || Double.TYPE.equals(cls)) {
                obj = Double.valueOf(value);
            }
        } else if (cls.isEnum()) {
            obj = Enum.valueOf(cls.asSubclass(Enum.class), value);
        }

        return cls.cast(obj);
    }


}


ConfigurationListener 接口

/**
* 配置侦听器,将在配置侦听更改时得到通知.
*/
public interface ConfigurationListener {

    /**
     * 侦听器回调方法. 一旦侦听器的配置发生任何更改,侦听器就会通过此方法得到通知.
     *
     * @param event config change event
     */
    void process(ConfigChangeEvent event);
}

DynamicConfiguration 接口

/**
* 动态配置
*
* 从框架内部的使用场景来看,主要有三种方法:
* 1.getConfig 从配置中心获取管理规则或单个配置项.
* 2.getConfigFile 在启动时从配置中心获取配置文件
* 3.addListener/removeListener 为需要监视的治理规则或配置项添加或删除侦听器.
*/
public interface DynamicConfiguration extends Configuration {
    String DEFAULT_GROUP = "dubbo";

    /**
     * {@link #addListener(String, String, ConfigurationListener)}
     *
     * @param key      the key to represent a configuration
     * @param listener configuration listener
     */
    default void addListener(String key, ConfigurationListener listener) {
        addListener(key, DEFAULT_GROUP, listener);
    }


    /**
     * {@link #removeListener(String, String, ConfigurationListener)}
     *
     * @param key      the key to represent a configuration
     * @param listener configuration listener
     */
    default void removeListener(String key, ConfigurationListener listener) {
        removeListener(key, DEFAULT_GROUP, listener);
    }

    /**
     * Register a configuration listener for a specified key
     * The listener only works for service governance purpose, so the target group would always be the value user
     * specifies at startup or 'dubbo' by default. This method will only register listener, which means it will not
     * trigger a notification that contains the current value.
     *
     * @param key      the key to represent a configuration
     * @param group    the group where the key belongs to
     * @param listener configuration listener
     */
    void addListener(String key, String group, ConfigurationListener listener);

    /**
     * Stops one listener from listening to value changes in the specified key.
     *
     * @param key      the key to represent a configuration
     * @param group    the group where the key belongs to
     * @param listener configuration listener
     */
    void removeListener(String key, String group, ConfigurationListener listener);

    /**
     * Get the governance rule mapped to the given key and the given group
     *
     * @param key   the key to represent a configuration
     * @param group the group where the key belongs to
     * @return target configuration mapped to the given key and the given group
     */
    default String getRule(String key, String group) {
        return getRule(key, group, -1L);
    }

    /**
     * Get the governance rule mapped to the given key and the given group. If the
     * rule fails to return after timeout exceeds, IllegalStateException will be thrown.
     *
     * @param key     the key to represent a configuration
     * @param group   the group where the key belongs to
     * @param timeout timeout value for fetching the target config
     * @return target configuration mapped to the given key and the given group, IllegalStateException will be thrown
     * if timeout exceeds.
     */
    String getRule(String key, String group, long timeout) throws IllegalStateException;

    /**
     * This method are mostly used to get a compound config file, such as a complete dubbo.properties file.
     * Also {@see #getConfig(String, String)}
     */
    default String getProperties(String key, String group) throws IllegalStateException {
        return getProperties(key, group, -1L);
    }

    /**
     * This method are mostly used to get a compound config file, such as a complete dubbo.properties file.
     * Also {@see #getConfig(String, String, long)}
     */
    String getProperties(String key, String group, long timeout) throws IllegalStateException;

    /**
     * Find DynamicConfiguration instance
     *
     * @return DynamicConfiguration instance
     */
    static DynamicConfiguration getDynamicConfiguration() {
        Optional<Configuration> optional = Environment.getInstance().getDynamicConfiguration();
        return (DynamicConfiguration) optional.orElseGet(() -> getExtensionLoader(DynamicConfigurationFactory.class)
                .getDefaultExtension()
                .getDynamicConfiguration(null));
    }

     /**
     * The format is '{interfaceName}:[version]:[group]'
     *
     * @return
     */
     static String getRuleKey(URL url) {
        return url.getColonSeparatedKey();
    }
}

DynamicConfigurationFactory 接口

定义了获取 DynamicConfiguration 的接口.

ConfigChangeType 枚举

定义了对配置项的操作,比如说新增、修改和删除.

ConfigChangeEvent 定义了对 Config 操作时产生的事件(观察者模式),最重要的就是 configType 这个属性值.

public class ConfigChangeEvent {
    private final String key;

    private final String value;
    private final ConfigChangeType changeType;

    public ConfigChangeEvent(String key, String value) {
        this(key, value, ConfigChangeType.MODIFIED);
    }

    public ConfigChangeEvent(String key, String value, ConfigChangeType changeType) {
        this.key = key;
        this.value = value;
        this.changeType = changeType;
    }

    public String getKey() {
        return key;
    }

    public String getValue() {
        return value;
    }

    public ConfigChangeType getChangeType() {
        return changeType;
    }

    @Override
    public String toString() {
        return "ConfigChangeEvent{" +
                "key='" + key + '\'' +
                ", value='" + value + '\'' +
                ", changeType=" + changeType +
                '}';
    }
}

AbstractDynamicConfigurationFactory 实现了 DynamicConfigurationFactory 的骨架,保证获取 DynamicConfiguration 是线程安全的.

NopDynamicConfiguration 实现的是一个没有任何操作的配置中心,为默认实现.

/**
* {@link DynamicConfiguration} 的默认扩展名. 如果用户未指定配置中心,或指定的配置扩展名无效,则默认为该配置中心.
*/
public class NopDynamicConfiguration implements DynamicConfiguration {

    public NopDynamicConfiguration(URL url) {
        // no-op
    }


    @Override
    public Object getInternalProperty(String key) {
        return null;
    }

    @Override
    public void addListener(String key, String group, ConfigurationListener listener) {
        // no-op
    }

    @Override
    public void removeListener(String key, String group, ConfigurationListener listener) {
        // no-op
    }

    @Override
    public String getRule(String key, String group, long timeout) throws IllegalStateException {
        return null;
    }

    @Override
    public String getProperties(String key, String group, long timeout) throws IllegalStateException {
        return null;
    }
}