Dubbo Config

Dubbo Config

AbstractConfig

这是dubbo所有的配置类的基类,除了id外没有实例属性了,主要还是提供了一些通用的方法。

protected static void appendProperties(AbstractConfig config) {
    if (config == null) {
        return;
    }
    //通过dubbo.+去掉后缀的类型+.得到前缀
    //例如ServiceConfig得到的就是dubbo.service.
    String prefix = "dubbo." + getTagName(config.getClass()) + ".";
    //遍历所有public方法
    Method[] methods = config.getClass().getMethods();
    for (Method method : methods) {
        try {
            String name = method.getName();
            //set方法
            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.getId() != null && config.getId().length() > 0) {
                    //有多个配置的时候通过id指定,例如dubbo.registry.a.timeout
                    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) {
                    //默认的属性,类似上例dubbo.registry.timeout
                    String pn = prefix + property;
                    value = System.getProperty(pn);
                    if (!StringUtils.isBlank(value)) {
                        logger.info("Use System Property " + pn + " to config dubbo");
                    }
                }
                if (value == null || value.length() == 0) {
                    Method getter;
                    try {
                        getter = config.getClass().getMethod("get" + name.substring(3));
                    } catch (NoSuchMethodException e) {
                        try {
                            getter = config.getClass().getMethod("is" + name.substring(3));
                        } catch (NoSuchMethodException e2) {
                            getter = null;
                        }
                    }
                    //环境变量没有得到就使用get方法
                    if (getter != null) {
                        //已经可以通过get方法得到了表明已经通过项目的配置文件配置了该属性
                        if (getter.invoke(config) == null) {
                            //如果get方法返回为空就加载dubbo.properties文件,该文件路径可以通过dubbo.properties.file键修改
                            //dubbo.properties文件中的配置也是先拿指定id的
                            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));
                                }
                            }

                        }
                    }
                }
                //通过set方法注入替换
                if (value != null && value.length() > 0) {
                    method.invoke(config, convertPrimitive(method.getParameterTypes()[0], value));
                }
            }
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
        }
    }
}

该方法的作用是通过反射添加属性,这里解释了为什么可以通过中间添加id配置,例如dubbo.registry.a.timeout,以及默认是没有id的。还有环境变量优先级最高,项目的配置文件次之,dubbo.properties文件是被优先级最低被加载的,该文件可以通过dubbo.properties.file指定修改。

@SuppressWarnings("unchecked")
protected static void appendParameters(Map<String, String> parameters, Object config, String prefix) {
    if (config == null) {
        return;
    }
    //遍历所有public方法
    Method[] methods = config.getClass().getMethods();
    for (Method method : methods) {
        try {
            String name = method.getName();
            //判断是否是get或者is方法,不是object的getClass方法,入参个数为0,返回类型是原始的或者包装类
            if ((name.startsWith("get") || name.startsWith("is"))
                    && !"getClass".equals(name)
                    && Modifier.isPublic(method.getModifiers())
                    && method.getParameterTypes().length == 0
                    && isPrimitive(method.getReturnType())) {
                        //Parameter注解
                Parameter parameter = method.getAnnotation(Parameter.class);
                //注解排除为true说明不需要注入,继续下个循环
                if (method.getReturnType() == Object.class || parameter != null && parameter.excluded()) {
                    continue;
                }
                //get的长度为3,is长度2
                int i = name.startsWith("get") ? 3 : 2;
                //用.将方法名默认为驼峰命名并隔开
                String prop = StringUtils.camelToSplitName(name.substring(i, i + 1).toLowerCase() + name.substring(i + 1), ".");
                String key;
                //注解制定的key或者经过处理的方法名
                if (parameter != null && parameter.key().length() > 0) {
                    key = parameter.key();
                } else {
                    key = prop;
                }
                //反射调用该方法
                Object value = method.invoke(config);
                String str = String.valueOf(value).trim();
                if (value != null && str.length() > 0) {
                    //url编码
                    if (parameter != null && parameter.escaped()) {
                        str = URL.encode(str);
                    }
                    //注解append为true表明该值需要添加
                    if (parameter != null && parameter.append()) {
                        //defalut值
                        String pre = parameters.get(Constants.DEFAULT_KEY + "." + key);
                        if (pre != null && pre.length() > 0) {
                            str = pre + "," + str;
                        }
                        //自身值
                        pre = parameters.get(key);
                        if (pre != null && pre.length() > 0) {
                            str = pre + "," + str;
                        }
                    }
                    //指定前缀
                    if (prefix != null && prefix.length() > 0) {
                        key = prefix + "." + key;
                    }
                    parameters.put(key, str);
                    //required为true但是该值为空抛出异常
                } else if (parameter != null && parameter.required()) {
                    throw new IllegalStateException(config.getClass().getSimpleName() + "." + key + " == null");
                }
                //getParameters方法的处理
            } else if ("getParameters".equals(name)
                    && Modifier.isPublic(method.getModifiers())
                    && method.getParameterTypes().length == 0
                    && method.getReturnType() == Map.class) {
                Map<String, String> map = (Map<String, String>) method.invoke(config, new Object[0]);
                if (map != null && map.size() > 0) {
                    String pre = (prefix != null && prefix.length() > 0 ? prefix + "." : "");
                    for (Map.Entry<String, String> entry : map.entrySet()) {
                        parameters.put(pre + entry.getKey().replace('-', '.'), entry.getValue());
                    }
                }
            }
        } catch (Exception e) {
            throw new IllegalStateException(e.getMessage(), e);
        }
    }
}

这个方法用来把dubbo的配置类中的属性放到map中,然后把这些属性添加到dubbo url中。

protected void appendAnnotation(Class<?> annotationClass, Object annotation) {
    //反射遍历注解的方法
    Method[] methods = annotationClass.getMethods();
    for (Method method : methods) {
        //不是Object的方法,不是返回void,参数个数为0,public,非static
        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();
                //两个方法的特殊处理,因为都是描述interface用的
                if ("interfaceClass".equals(property) || "interfaceName".equals(property)) {
                    property = "interface";
                }
                //同样名字的set方法
                String setter = "set" + property.substring(0, 1).toUpperCase() + property.substring(1);
                //对注解对象反射调用该方法
                Object value = method.invoke(annotation);
                if (value != null && !value.equals(method.getDefaultValue())) {
                    //方法返回类型(原始类型转为包装类型))
                    Class<?> parameterType = ReflectUtils.getBoxedClass(method.getReturnType());
                    //filter和listener是String[]类型的,转为String
                    if ("filter".equals(property) || "listener".equals(property)) {
                        parameterType = String.class;
                        value = StringUtils.join((String[]) value, ",");
                        //parameters转为键值一一对应的map
                    } else if ("parameters".equals(property)) {
                        parameterType = Map.class;
                        value = CollectionUtils.toStringMap((String[]) value);
                    }
                    try {
                        //对当前类的set方法进行注入,即将注解的属性注入当前对象
                        Method setterMethod = getClass().getMethod(setter, parameterType);
                        setterMethod.invoke(this, value);
                    } catch (NoSuchMethodException e) {
                    }
                }
            } catch (Throwable e) {
                logger.error(e.getMessage(), e);
            }
        }
    }
}

这个方法用来将Reference和Service注解的值通过相同名字的set方法注入自身对象,注意这里必须不等于默认值,像retries默认等于0的就不能通过设置为0关闭重试,可以设置-1关闭重试。该类还有一个toString方法,没有细看,不过只要debug就能看到这些配置对象的toString的值了。

dubboconfig.png
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 200,738评论 5 472
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 84,377评论 2 377
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 147,774评论 0 333
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,032评论 1 272
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,015评论 5 361
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,239评论 1 278
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,724评论 3 393
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,374评论 0 255
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,508评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,410评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,457评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,132评论 3 316
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,733评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,804评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,022评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,515评论 2 346
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,116评论 2 341

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,566评论 18 139
  • Dubbo是什么 Dubbo是Alibaba开源的分布式服务框架,它最大的特点是按照分层的方式来架构,使用这种方式...
    Coselding阅读 17,159评论 3 196
  • Spring Boot 参考指南 介绍 转载自:https://www.gitbook.com/book/qbgb...
    毛宇鹏阅读 46,714评论 6 342
  • 如果足够热爱,那么不需要坚持却能坚持很久。 前段时间看过一篇毒鸡汤,里面有几句话是这样说的: 为什么我们总在说坚持...
    诗城冀遇阅读 286评论 0 0
  • 阳阳_b656阅读 196评论 0 0