private static final Map<String, String> LEGACY_PROPERTIES = new HashMap<String, String>();
private static final String[] SUFFIXES = new String[]{"Config", "Bean", "ConfigBase"}; //Config对象名的后缀
static { //已过时的属性(将一些旧版本使用的属性与当前的属性进行映射,起到适配转换的作用)
LEGACY_PROPERTIES.put("dubbo.protocol.name", "dubbo.service.protocol");
LEGACY_PROPERTIES.put("dubbo.protocol.host", "dubbo.service.server.host");
LEGACY_PROPERTIES.put("dubbo.protocol.port", "dubbo.service.server.port");
LEGACY_PROPERTIES.put("dubbo.protocol.threads", "dubbo.service.max.thread.pool.size");
LEGACY_PROPERTIES.put("dubbo.consumer.timeout", "dubbo.service.invoke.timeout");
LEGACY_PROPERTIES.put("dubbo.consumer.retries", "dubbo.service.max.retry.providers");
LEGACY_PROPERTIES.put("dubbo.consumer.check", "dubbo.service.allow.no.provider");
LEGACY_PROPERTIES.put("dubbo.service.url", "dubbo.service.address");
}
protected String id; //配置id(所有config子类都有)
protected String prefix; //配置对象名的前缀
public static void appendParameters(Map<String, String> parameters, Object config, String prefix) { //将Config对象的属性添加到参数Map中(将Config对象中的属性值进行筛选处理,并添加的参数Map中)
if (config == null) {
return;
}
Method[] methods = config.getClass().getMethods(); //利用反射,获取config对象中的所有public方法
for (Method method : methods) { //遍历Config对象的方法,找到getXxx()、isXxx()或getParameters()方法进行处理
try {
String name = method.getName();
if (MethodUtils.isGetter(method)) {
Parameter parameter = method.getAnnotation(Parameter.class); //取出方法上声明的注解@Parameter
if (method.getReturnType() == Object.class || parameter != null && parameter.excluded()) { //方法返回值为对象或在声明@Parameter且参数被排除时,跳过不处理
continue;
}
String key; //Config对象的属性名
if (parameter != null && parameter.key().length() > 0) { //若方法使用了@Parameter注解声明,且设置了key的值,则将该值作为参数key
key = parameter.key();
} else { //没有带@Parameter注解
key = calculatePropertyFromGetter(name); //提取属性名,如getProtocol()方法的属性名为protocol(若属性名是驼峰的,则按分隔符处理,如getProtocolName(),若分隔符为".",则最终的属性名为protocol.name)
}
Object value = method.invoke(config); //使用反射机制,获取config中get或is方法的返回值
String str = String.valueOf(value).trim();
if (value != null && str.length() > 0) {
if (parameter != null && parameter.escaped()) {
str = URL.encode(str); //若escaped指定是需要编码的,则编码字符串
}
if (parameter != null && parameter.append()) { //若相同的key对应多个值,且@Parameter注解中的append=true,则通过分隔符","将多个值拼接
String pre = parameters.get(key); //将自定义参数Map中的值与Config中的属性值,进行拼接
if (pre != null && pre.length() > 0) {
str = pre + "," + str; //带上分隔符,附加到原有的值value上
}
}
if (prefix != null && prefix.length() > 0) {
key = prefix + "." + key; //使用前缀与参数key进行拼接
}
parameters.put(key, str); //将参数key、value,写入到参数Map中
} else if (parameter != null && parameter.required()) { //在值value为空,且@parameter注解required声明为必须时,报出异常信息
throw new IllegalStateException(config.getClass().getSimpleName() + "." + key + " == null");
}
} else if (isParametersGetter(method)) { //若是getParameters()方法,则可以将该方法的返回值Map直接设置到处理的参数map中
Map<String, String> map = (Map<String, String>) method.invoke(config, new Object[0]);
parameters.putAll(convert(map, prefix)); //map中的参数依次带上前缀,并添加到参数Map中
}
} catch (Exception e) {
throw new IllegalStateException(e.getMessage(), e);
}
}
}
protected void appendAnnotation(Class<?> annotationClass, Object annotation) {
Method[] methods = annotationClass.getMethods();
for (Method method : methods) { //遍历注解Class中的所有方法
if (method.getDeclaringClass() != Object.class
&& method.getReturnType() != void.class
&& method.getParameterTypes().length == 0
&& Modifier.isPublic(method.getModifiers())
&& !Modifier.isStatic(method.getModifiers())) { //找出注解中 公有的、非静态的,且有返回值的方法
try {
String property = method.getName(); //获取方法名(即为注解的属性名)
if ("interfaceClass".equals(property) || "interfaceName".equals(property)) {
property = "interface"; //归并属性名
}
String setter = "set" + property.substring(0, 1).toUpperCase() + property.substring(1); //将注解中的方法名,组装为config对象实例的set方法名,如setListener
Object value = method.invoke(annotation); //获取注解中方法对应的值
if (value != null && !value.equals(method.getDefaultValue())) { //注解方法中值不为空且不为默认值时,将注解方法中的返回值写到Config对象中
Class<?> parameterType = ReflectUtils.getBoxedClass(method.getReturnType()); //获取返回类型的封装类型
if ("filter".equals(property) || "listener".equals(property)) { //属性为filter(过滤器)、listener(监听器)时,是按数组配置的
parameterType = String.class;
value = StringUtils.join((String[]) value, ","); //将字符串数组按分隔符拼接为字符串
} else if ("parameters".equals(property)) { //属性为parameters,是按Map配置的(字符数组是按key、value形式依次存储的)
parameterType = Map.class;
value = CollectionUtils.toStringMap((String[]) value);
}
try {
Method setterMethod = getClass().getMethod(setter, parameterType); //获取Config对象对应的setter方法
setterMethod.invoke(this, value); //使用反射机制,调用setter方法,将注解方法中的返回值写到Config对象中
} catch (NoSuchMethodException e) {
// ignore
}
}
} catch (Throwable e) {
logger.error(e.getMessage(), e);
}
}
}
}
public Map<String, String> getMetaData() { //获取Config对象中的元数据(找到元数据方法或getParameters方法,进行方法调用并获取到返回值,最后设置到元数据Map中)
Map<String, String> metaData = new HashMap<>();
Method[] methods = this.getClass().getMethods(); //this.getClass() 指的是AbstractConfig的实例对象,比如ConfigCenterConfig
for (Method method : methods) {
try {
String name = method.getName();
if (MethodUtils.isMetaMethod(method)) { //判断是否是获取元数据方法(public的get/is方法,且返回值是基本类型)
String key;
Parameter parameter = method.getAnnotation(Parameter.class);
if (parameter != null && parameter.key().length() > 0 && parameter.useKeyAsProperty()) {
key = parameter.key(); //若方法上带有@Parameter注解,则直接取注解中key的值
} else {
key = calculateAttributeFromGetter(name); //若没有带有@Parameter注解或配置key,则从方法名中取出属性名
}
if (method.getReturnType() == Object.class) {
metaData.put(key, null);
continue;
}
if (MethodUtils.isDeprecated(method) && metaData.get(key) != null) { //若方法已经弃用了,则不再处理
continue;
}
Object value = method.invoke(this); //使用反射调用对应方法,并接收返回值
String str = String.valueOf(value).trim();
if (value != null && str.length() > 0) {
metaData.put(key, str); //将配置对象中的key、value设置到元数据中
} else {
metaData.put(key, null);
}
} else if (isParametersGetter(method)) { //判断是否是getParameters方法
Map<String, String> map = (Map<String, String>) method.invoke(this, new Object[0]); //调用getParameters()方法,new Object[0]表明没有参数
metaData.putAll(convert(map, ""));
}
} catch (Exception e) {
throw new IllegalStateException(e.getMessage(), e);
}
}
return metaData;
}
public void refresh() { //刷新Config对象的属性值
Environment env = ApplicationModel.getEnvironment(); //获取环境信息
try {
CompositeConfiguration compositeConfiguration = env.getPrefixedConfiguration(this); //获取带有前缀的合成配置对象的实例(包含多种配置源对象的实例)
// loop methods, get override value and set the new value back to method
Method[] methods = getClass().getMethods();
for (Method method : methods) { //遍历当前配置对象的方法,从合成的配置实例中获取值,通过set()方法或setParameters()方法设置到XxxConfig对象中
if (MethodUtils.isSetter(method)) { //是否是setXXX()方法
try {
String value = StringUtils.trim(compositeConfiguration.getString(extractPropertyName(getClass(), method))); //从配置源获取属性对应的值
// isTypeMatch() is called to avoid duplicate and incorrect update, for example, we have two 'setGeneric' methods in ReferenceConfig.
if (StringUtils.isNotEmpty(value) && ClassUtils.isTypeMatch(method.getParameterTypes()[0], value)) { //若值不为空,且参数类型与参数值能够匹配,则执行invoke调用
method.invoke(this, ClassUtils.convertPrimitive(method.getParameterTypes()[0], value)); //调用set方法对Config对象的属性设置
}
} catch (NoSuchMethodException e) {
logger.info("Failed to override the property " + method.getName() + " in " +
this.getClass().getSimpleName() +
", please make sure every property has getter/setter method provided.");
}
} else if (isParametersSetter(method)) { //是否是setParameters()方法
String value = StringUtils.trim(compositeConfiguration.getString(extractPropertyName(getClass(), method))); //value的格式如:"[{key1:value1},{key2:value2}...]"
if (StringUtils.isNotEmpty(value)) {
Map<String, String> map = invokeGetParameters(getClass(), this); //获取Config对象中getParameters()方法的返回值
map = map == null ? new HashMap<>() : map;
map.putAll(convert(StringUtils.parseParameters(value), "")); //将属性值解析为Map形式,并设置到配置对象Config的Map
invokeSetParameters(getClass(), this, map); //调用setParameters()方法,对Config对象的参数设值
}
}
}
} catch (Exception e) {
logger.error("Failed to override ", e);
}
}
private final PropertiesConfiguration propertiesConfiguration; //装载"dubbo.properties"文件的配置信息
private final SystemConfiguration systemConfiguration; //装载System的properties配置系信息
private final EnvironmentConfiguration environmentConfiguration;//装载JVM环境变量的配置信息
private final InmemoryConfiguration externalConfiguration; //配置中心的额外配置(装载配置中心配置,存入到本地缓存中)
private final InmemoryConfiguration appExternalConfiguration; //配置中心按group隔离的配置(装载配置中心的配置信息)
private CompositeConfiguration globalConfiguration; //合成的配置信息
private Map<String, String> externalConfigurationMap = new HashMap<>(); //配置中心的额外配置对应的Map(从配置中心拉取的未按group隔离的配置内容)
private Map<String, String> appExternalConfigurationMap = new HashMap<>(); //配置中心按group隔离的配置对应的Map(按应用名做group隔离的配置内容)
private boolean configCenterFirst = true; //配置中心的配置是否优先
private DynamicConfiguration dynamicConfiguration; //动态配置实例
public void initialize() throws IllegalStateException { //用配置中心的配置做初始化(对当前对象的属性进行初始化)
ConfigManager configManager = ApplicationModel.getConfigManager(); //获取配置管理对象实例(通过SPI机制获取)
Optional<Collection<ConfigCenterConfig>> defaultConfigs = configManager.getDefaultConfigCenter(); //获取默认配置中心列表
defaultConfigs.ifPresent(configs -> { //ifPresent:若值存在时,带着值执行对应的动作,否则什么都不做
for (ConfigCenterConfig config : configs) { //从默认配置中心获取配置值,设置到当前的缓存中(若有多个默认的配置中心,会出现值覆盖)
this.setExternalConfigMap(config.getExternalConfiguration());
this.setAppExternalConfigMap(config.getAppExternalConfiguration());
}
});
this.externalConfiguration.setProperties(externalConfigurationMap);
this.appExternalConfiguration.setProperties(appExternalConfigurationMap);
}
public synchronized CompositeConfiguration getPrefixedConfiguration(AbstractConfig config) { //获取Config对应的合成配置
CompositeConfiguration prefixedConfiguration = new CompositeConfiguration(config.getPrefix(), config.getId());
Configuration configuration = new ConfigConfigurationAdapter(config); //AbstractConfig对应的配置对象的实例
if (this.isConfigCenterFirst()) { //配置中心的配置优先(即配置中心的配置高于Config的配置)
// 在CompositeConfiguration#getInternalProperty进行取值时,会依次遍历列表中的配置对象的实例,越靠前的配置,越先获取到配置值。
prefixedConfiguration.addConfiguration(systemConfiguration); //systemConfiguration、environmentConfiguration等对象,在Environment构造函数中初始化的
prefixedConfiguration.addConfiguration(environmentConfiguration);
prefixedConfiguration.addConfiguration(appExternalConfiguration); //appExternalConfiguration、externalConfiguration的值来源于配置中心(在initialize方法中设置的值)
prefixedConfiguration.addConfiguration(externalConfiguration);
prefixedConfiguration.addConfiguration(configuration);
prefixedConfiguration.addConfiguration(propertiesConfiguration);
} else { //systemConfiguration、environmentConfiguration、propertiesConfiguration位置固定,主要根据isConfigCenterFirst()的值来调整 配置中心的位置
// Config center has the highest priority(配置中心有最高优先级)
prefixedConfiguration.addConfiguration(systemConfiguration);
prefixedConfiguration.addConfiguration(environmentConfiguration);
prefixedConfiguration.addConfiguration(configuration); //相比上面,配置信息加载的位置不一样
prefixedConfiguration.addConfiguration(appExternalConfiguration);
prefixedConfiguration.addConfiguration(externalConfiguration);
prefixedConfiguration.addConfiguration(propertiesConfiguration);
}
return prefixedConfiguration;
}
MetricsConfig这个配置对象的功能用途是怎样的?
AbstractConfig#refresh该处的刷新操作都做哪些功能?
Environment#getPrefixedConfiguration该方法中的配置中心加载位置会影响到哪些功能?
org.apache.dubbo.config.support.Parameter这个注解是怎么使用的?
Config相关对象是怎么注册为spring的bean的?
AbstractMethodConfig中的parameters自定义参数是怎样判断以及设定的?一定要带上spring的p的命名空间吗?
ServiceBean是怎么与具体的服务关联起来的?
为什么System.setProperty设置的值,config对应能取到值?如:System.setProperty(“dubbo.application.name”, “demo”);设置的值,applicationConfig.getName()能取到值?
Config与Model两个数据模型的功能用途有何不同?
Config的前缀是怎样计算出来的,如ApplicationConfig对应为"dubbo.application." ?
public String getPrefix() { //获取Config的前缀名(若没有设置,则使用默认的前缀名,如ApplicationConfig对应的前缀为"dubbo.application")
return StringUtils.isNotEmpty(prefix) ? prefix : (CommonConstants.DUBBO + "." + getTagName(this.getClass()));
}
public static String getTagName(Class<?> cls) { //获取Config类对应的标签名,比如ConfigCenter为config-center
String tag = cls.getSimpleName(); //如ConfigCenterConfig,tag为ConfigCenterConfig
for (String suffix : SUFFIXES) { //若类名包含指定后缀名,则先去除掉后缀
if (tag.endsWith(suffix)) { //把包含的后缀去掉,比如ConfigCenterConfig改为ConfigCenter,又如ApplicationConfig对应为Application
tag = tag.substring(0, tag.length() - suffix.length());
break;
}
}
return StringUtils.camelToSplitName(tag, "-"); //将驼峰字符串转换为按分隔符处理
}
ApplicationConfig中的hostname是在哪里设置的?值从哪里获取的?
ConfigConfigurationAdapter的功能用途是什么?
AbstractMethodConfig#forks是怎样实现并行调用数的?与AbstractMethodConfig#actives并发调用数有什么区别?
AbstractMethodConfig#sent的用途是什么?
AbstractServiceConfig#delay延迟时间和超时时间timeOut有什么区别?