美文网首页
Method getAnnotations顺序

Method getAnnotations顺序

作者: jeho0815 | 来源:发表于2018-11-20 20:02 被阅读0次

    问题背景

    在使用ServiceComb开发的进程启动时,生成契约偶现不一致(描述偶尔为空,导致赋值了一个默认的描述),导致服务注册不上。开发定位过程中,最后发现是因为getAnnotations这个方法返回的顺序order不一致。所以只能看下源码为啥会出现这种情况。

    源码分析

    从Method方法跟踪getAnnotations,最终会调用Executable.getDeclaredAnnotations

        /**
         * {@inheritDoc}
         */
        public Annotation[] getDeclaredAnnotations()  {
            return AnnotationParser.toArray(declaredAnnotations());
        }
    
        private transient Map<Class<? extends Annotation>, Annotation> declaredAnnotations;
    
        private synchronized  Map<Class<? extends Annotation>, Annotation> declaredAnnotations() {
            if (declaredAnnotations == null) {
                Executable root = getRoot();
                if (root != null) {
                    declaredAnnotations = root.declaredAnnotations();
                } else {
                    declaredAnnotations = AnnotationParser.parseAnnotations(
                        getAnnotationBytes(),
                        sun.misc.SharedSecrets.getJavaLangAccess().
                        getConstantPool(getDeclaringClass()),
                        getDeclaringClass());
                }
            }
            return declaredAnnotations;
        }
    

    这个是declaredAnnotations是返回一个map,所以需要排查下这个方法返回的AnnotationParser.parseAnnotations 是否有序。
    跟踪到AnnotationParser实现里面,这个需要下载openjdk得源码才可以。

    private static Map<Class<? extends Annotation>, Annotation> parseAnnotations2(
                    byte[] rawAnnotations,
                    ConstantPool constPool,
                    Class<?> container,
                    Class<? extends Annotation>[] selectAnnotationClasses) {
            Map<Class<? extends Annotation>, Annotation> result =
                new LinkedHashMap<Class<? extends Annotation>, Annotation>();
            ByteBuffer buf = ByteBuffer.wrap(rawAnnotations);
            int numAnnotations = buf.getShort() & 0xFFFF;
            for (int i = 0; i < numAnnotations; i++) {
                Annotation a = parseAnnotation2(buf, constPool, container, false, selectAnnotationClasses);
                if (a != null) {
                    Class<? extends Annotation> klass = a.annotationType();
                    if (AnnotationType.getInstance(klass).retention() == RetentionPolicy.RUNTIME &&
                        result.put(klass, a) != null) {
                            throw new AnnotationFormatError(
                                "Duplicate annotation for class: "+klass+": " + a);
                }
            }
            }
            return result;
        }
    

    rawAnnotations是一个byte数组,是Method.getAnnotationBytes返回的,这个是从class文件加载得到的,编译是什么样的就返回什么样的,map也是一个LinkedHashMap,可以保证顺序。所以正常情况肯定是有序的,所以就排查了代码的问题。

    问题原因

    最后通过打印getAnnotations数组,发现多了很多其他的注解,就怀疑是不是启动过程中有别的东西对它进行了修改。最终发现是启动过程中设置了一个javaagent,这个agent会织入一些注解,顺序可能会重新排,导致会随机出现一些该问题。

    相关文章

      网友评论

          本文标题:Method getAnnotations顺序

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