1、参考了SpringCloud系列八:自定义Ribbon配置 - 禁忌夜色153 - 博客园进行自定义Ribbon配置,开始觉得自定义注解麻烦,所以通过后面介绍的在配置文件中进行设置,实验成功。后来觉得要不试试自定义注解的方式,按照文件介绍先定义了扫描排除注解【ExcludeComponent】,然后注解配置类【RibbonConfiguration】。这样就可以预期在应用启动时配置类【RibbonConfiguration】不会实例化,并且只有在访问eureka实例【user】时才会应用自定义的Ribbon负载均衡器。但测试发现自定义配置类【RibbonConfiguration】总是在应用启动时就实例化,并且会成为默认的负载均衡器,扫描排除注解【ExcludeComponent】似乎并未起作用。
2、为了找到出现问题的原因,一步步追踪SpringBoot的启动过程,最后发现是由于没有在排除注解【ExcludeComponent】上设置元注解【Retention】。
3、在这个追寻过程了,除了弄明白了出现问题的原因,还了解了一部门SpringBoot的启动加载过程。
4、在SpringBoot的启动过程中,在遍历启动类所在包下的类文件时,其实是找了排除注解【ExcludeComponent】所在的类文件的。
5、问题出在遍历配置类【RibbonConfiguration】时,要构建其元数据读取器。
在通过一步步调用后,最终要通过读取【RibbonConfiguration.class】文件来构建出此类的元数据。
6、在读取【.class】文件时,将注解【@Configuration】读取到属性【RUNTIME_VISIBLE_ANNOTATIONS】中,将注解【@ExcludeComponent】读取到属性【RUNTIME_INVISIBLE_ANNOTATIONS】中。
处理不可见注解属性【RUNTIME_INVISIBLE_ANNOTATIONS】时,由于不可见则直接返回空的注解访问器。
7、在由类访问器【ClassVisitor】通过方法【visitAnnotation】创建注解访问器【AnnotationVisitor】时,会将其直接注解集合的【增加】方法以lambda表达式的形式【this.annotations::add】传给注解访问器的消费者属性【consumer】。在注解访问完成后会调用其【visitEnd】方法,从而实现将找到的注解添加到【ClassVisitor】的注解集合中。
对于不可见的注解,由于获取的注解访问器直接为空,所以也就不会执行对类访问器注解集合的增加操作。
在对类文件的所有属性都读取并处理完毕后,也会调用类访问器的【visitEnd】方法,从而将收集的类相关属性整合到类访问器的【metaData】属性中。
然后被元数据阅读器获取。
然后Spring根据元数据中的注解,判断当前类是否是为可实例化的备选组件类。
8、补充
类的元数据是类读取器【ClassReader】通过读取类文件获取的,在初始化类读取器时会通过输入流获取类文件的内容。