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;
}
}
/**
* 配置中心接口,
*/
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;
}
}
上一篇: 精仿网易严选微信小程序配置教程 小程序
下一篇: Docker使用小贴士
推荐阅读
-
[Abp 源码分析]四、模块配置
-
kubernetes垃圾回收器GarbageCollector源码分析(一)
-
[Abp vNext 源码分析] - 11. 用户的自定义参数与配置
-
Flink中watermark为什么选择最小一条(源码分析)
-
Python的socket模块源码中的一些实现要点分析
-
STL源码分析之第二级配置器
-
Tomcat源码分析三:Tomcat启动加载过程(一)的源码解析
-
九、Spring之BeanFactory源码分析(一)
-
Mybaits 源码解析 (九)----- 全网最详细,没有之一:一级缓存和二级缓存源码分析
-
Tomcat源码分析 (六)----- Tomcat 启动过程(一)