Skip to content

2.7.2版本.关于AbstractConfig中getMetaData获取generic值的问题 #6186

Closed
@horizonzy

Description

@horizonzy
Member
    public Map<String, String> getMetaData() {
        metaData = new HashMap<>();
        Method[] methods = this.getClass().getMethods();
        for (Method method : methods) {
            try {
                String name = method.getName();
                if ((name.startsWith("get") || name.startsWith("is"))
                        && !name.equals("get")
                        && !"getClass".equals(name)
                        && Modifier.isPublic(method.getModifiers())
                        && method.getParameterTypes().length == 0
                        && isPrimitive(method.getReturnType())) {
                    int i = name.startsWith("get") ? 3 : 2;
                    String prop = StringUtils.camelToSplitName(name.substring(i, i + 1).toLowerCase() + name.substring(i + 1), ".");
                    String key;
                    Parameter parameter = method.getAnnotation(Parameter.class);
                    if (parameter != null && parameter.key().length() > 0) {
                        key = parameter.key();
                    } else {
                        key = prop;
                    }
                    // treat url and configuration differently, the value should always present in configuration though it may not need to present in url.
                    //if (method.getReturnType() == Object.class || parameter != null && parameter.excluded()) {
                    if (method.getReturnType() == Object.class) {
                        metaData.put(key, null);
                        continue;
                    }
                    Object value = method.invoke(this);
                    String str = String.valueOf(value).trim();
                    if (value != null && str.length() > 0) {
                        if (parameter != null && parameter.escaped()) {
                            str = URL.encode(str);
                        }
                        if (parameter != null && parameter.append()) {
                            String pre = String.valueOf(metaData.get(Constants.DEFAULT_KEY + "." + key));
                            if (pre != null && pre.length() > 0) {
                                str = pre + "," + str;
                            }
                            pre = String.valueOf(metaData.get(key));
                            if (pre != null && pre.length() > 0) {
                                str = pre + "," + str;
                            }
                        }
                      /*  if (prefix != null && prefix.length() > 0) {
                            key = prefix + "." + key;
                        }*/
                        metaData.put(key, str);
                    } else {
                        metaData.put(key, null);
                    }
                    // TODO check required somewhere else.
                    /*else if (parameter != null && parameter.required()) {
                        throw new IllegalStateException(this.getClass().getSimpleName() + "." + key + " == null");
                    }*/
                } 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(this, 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()) {
                            metaData.put(entry.getKey().replace('-', '.'), entry.getValue());
                        }
                    }
                }
            } catch (Exception e) {
                System.out.println(this.getClass().getName());
                System.out.println(method.getName());
                throw new IllegalStateException(e.getMessage(), e);
            }
        }
        return metaData;
    }

我在provider端通过泛化的方式提供服务,providers的参数generic=true.在consumer端没有配置generic的值。在mergeUrl的时候应该会拿providerUrl的generic参数。最终consumer端的url的generic应该为true,但是最终发现mergeUrl之后的url的generic=false了,导致后续consumer端调用异常,最后追踪发现在consume端,consumerConfig的refresh发现了问题,这里通过反射获取当前对象的所有方法,如果isGeneric方法在getGeneric后面执行的话,会导致isGeneric的值覆盖掉getGeneric的值。

关于这行代码也许可以改成

  if (method.getReturnType() == Object.class) {
                        metaData.put(key, null);
                        continue;
                    }

->

      if (method.getReturnType() == Object.class || parameter != null && parameter.excluded()) {
                        metaData.putIfAbsent(key, null);
                        continue;
                    }

这样既可以解决掉上面那种场景,也可以避免设置了genric=true,但是被null覆盖掉的场景。

Activity

horizonzy

horizonzy commented on May 19, 2020

@horizonzy
MemberAuthor

@mercyblitz 小马哥看看

shengchaojie

shengchaojie commented on Aug 5, 2020

@shengchaojie

@horizonzy 我也遇到了这个问题,我感觉在mergeurl的时候,应该判断是让provider url 的generic配置 覆盖消费者的配置

shengchaojie

shengchaojie commented on Aug 5, 2020

@shengchaojie

generic 在泛化实现这个场景下 比较特殊,其他的配置都是本地为主,但是泛化实现是提供者端去控制消费者端的行为,所以要以提供者端=true的情况为主,如果provider的generic=true 那么无条件覆盖消费者端的,如果为false,那么不修改消费者端 @mercyblitz

horizonzy

horizonzy commented on Nov 12, 2020

@horizonzy
MemberAuthor

过了几个月来看。pr-#4678 fix了这个问题

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

      Development

      No branches or pull requests

        Participants

        @shengchaojie@horizonzy

        Issue actions

          2.7.2版本.关于AbstractConfig中getMetaData获取generic值的问题 · Issue #6186 · apache/dubbo