Dubbo源码导入Eclipse,打开源码,源码的结构分为cluster、common、container、filter、monitor、plugin、registry、remoting、rpc、serialization、lite部分。从代码的结构上来讲,Dubbo采用SPI的代码结构,即所有的结构都有可实现的接口。
首先从dubbo-config-api组件开始,其为配置文件解析做准备。结构上包括config、annotation、invoker、modal、support和utils构成。其中ServiceConfig为重点,其负责服务配置文件解析,它集成自AbstractServiceConfig(本类负责服务配置的数据结构),其顶级类继承自AbstractConfig(此类负责基本的属性、标注解析)。
AbstractConfig继承自
Serializable接口,另外它还启动了虚拟关闭进程,即虚拟机关闭时自动关闭相关的协议配置文件。其实现的代码如下:
Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() {
public void run() {
if (logger.isInfoEnabled()) {
logger.info("Run shutdown hook now.");
}
ProtocolConfig.destroyAll();
}
}, "DubboShutdownHook"));
}
public void run() {
if (logger.isInfoEnabled()) {
logger.info("Run shutdown hook now.");
}
ProtocolConfig.destroyAll();
}
}, "DubboShutdownHook"));
}
另外,为了实现服务程序的解析具备appendProperties、appendParameters、appendAttributes和appendAnnotation关键方法,每种方法通过反射机制实现相应属性和方法的添加。
appendProperties完成相应属性的调用,具体的实现代码如下:
protected static void appendProperties(AbstractConfig config) {
if (config == null) {
return;
}
String prefix = "dubbo." + getTagName(config.getClass()) + ".";
Method[] methods = config.getClass().getMethods(); //1)获取当前对象的方法;
for (Method method : methods) {//2)遍历方法,判断方法为Set方法。
try {
String name = method.getName();
if (name.length() > 3 && name.startsWith("set") && Modifier.isPublic(method.getModifiers())
&& method.getParameterTypes().length == 1 && isPrimitive(method.getParameterTypes()[0])) {
String property = StringUtils.camelToSplitName(name.substring(3, 4).toLowerCase() + name.substring(4), ".");
String value = null;
if (config == null) {
return;
}
String prefix = "dubbo." + getTagName(config.getClass()) + ".";
Method[] methods = config.getClass().getMethods(); //1)获取当前对象的方法;
for (Method method : methods) {//2)遍历方法,判断方法为Set方法。
try {
String name = method.getName();
if (name.length() > 3 && name.startsWith("set") && Modifier.isPublic(method.getModifiers())
&& method.getParameterTypes().length == 1 && isPrimitive(method.getParameterTypes()[0])) {
String property = StringUtils.camelToSplitName(name.substring(3, 4).toLowerCase() + name.substring(4), ".");
String value = null;
//3)获取系统属性的参数类型和值;
if (config.getId() != null && config.getId().length() > 0) {
String pn = prefix + config.getId() + "." + property;
value = System.getProperty(pn);
if (!StringUtils.isBlank(value)) {
logger.info("Use System Property " + pn + " to config dubbo");
}
}
if (value == null || value.length() == 0) {
String pn = prefix + property;
value = System.getProperty(pn);
if (!StringUtils.isBlank(value)) {
logger.info("Use System Property " + pn + " to config dubbo");
}
}
if (config.getId() != null && config.getId().length() > 0) {
String pn = prefix + config.getId() + "." + property;
value = System.getProperty(pn);
if (!StringUtils.isBlank(value)) {
logger.info("Use System Property " + pn + " to config dubbo");
}
}
if (value == null || value.length() == 0) {
String pn = prefix + property;
value = System.getProperty(pn);
if (!StringUtils.isBlank(value)) {
logger.info("Use System Property " + pn + " to config dubbo");
}
}
//4)如果3为空,则获取系统属性的类型和值;
if (value == null || value.length() == 0) {
Method getter;
try {
getter = config.getClass().getMethod("get" + name.substring(3), new Class<?>[0]);
} catch (NoSuchMethodException e) {
try {
getter = config.getClass().getMethod("is" + name.substring(3), new Class<?>[0]);
} catch (NoSuchMethodException e2) {
getter = null;
}
}
if (getter != null) {
if (getter.invoke(config, new Object[0]) == null) {
if (config.getId() != null && config.getId().length() > 0) {
value = ConfigUtils.getProperty(prefix + config.getId() + "." + property);
}
if (value == null || value.length() == 0) {
value = ConfigUtils.getProperty(prefix + property);
}
if (value == null || value.length() == 0) {
String legacyKey = legacyProperties.get(prefix + property);
if (legacyKey != null && legacyKey.length() > 0) {
value = convertLegacyValue(legacyKey, ConfigUtils.getProperty(legacyKey));
}
}
}
}
}
if (value == null || value.length() == 0) {
Method getter;
try {
getter = config.getClass().getMethod("get" + name.substring(3), new Class<?>[0]);
} catch (NoSuchMethodException e) {
try {
getter = config.getClass().getMethod("is" + name.substring(3), new Class<?>[0]);
} catch (NoSuchMethodException e2) {
getter = null;
}
}
if (getter != null) {
if (getter.invoke(config, new Object[0]) == null) {
if (config.getId() != null && config.getId().length() > 0) {
value = ConfigUtils.getProperty(prefix + config.getId() + "." + property);
}
if (value == null || value.length() == 0) {
value = ConfigUtils.getProperty(prefix + property);
}
if (value == null || value.length() == 0) {
String legacyKey = legacyProperties.get(prefix + property);
if (legacyKey != null && legacyKey.length() > 0) {
value = convertLegacyValue(legacyKey, ConfigUtils.getProperty(legacyKey));
}
}
}
}
}
//5)覆盖性操作。
if (value != null && value.length() > 0) {
method.invoke(config, new Object[]{convertPrimitive(method.getParameterTypes()[0], value)});
}
}
} catch (Exception e) {
logger.error(e.getMessage(), e);
}
}
}
if (value != null && value.length() > 0) {
method.invoke(config, new Object[]{convertPrimitive(method.getParameterTypes()[0], value)});
}
}
} catch (Exception e) {
logger.error(e.getMessage(), e);
}
}
}
其实现思路:
1)获取当前对象的方法;
2)遍历方法,判断方法为Set方法。
3)获取系统属性的参数类型和值;
4)如果3为空,则获取系统属性的类型和值;
5)覆盖性操作。
其他类的思路同上。通过以上的分析,不难发现Dubbo的配置文件采用不同的覆盖策略,其包括属性文件、配置文件和注解。