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】通過讀取類文件獲取的,在初始化類讀取器時會通過輸入流獲取類文件的內容。