美文网首页
Dubbo Config

Dubbo Config

作者: outwar | 来源:发表于2018-09-15 14:27 被阅读0次

    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

    相关文章

      网友评论

          本文标题:Dubbo Config

          本文链接:https://www.haomeiwen.com/subject/xvazgftx.html