精品欧美一区二区三区在线观看 _久久久久国色av免费观看性色_国产精品久久在线观看_亚洲第一综合网站_91精品又粗又猛又爽_小泽玛利亚一区二区免费_91亚洲精品国偷拍自产在线观看 _久久精品视频在线播放_美女精品久久久_欧美日韩国产成人在线

你知道什么是 @Component 注解的派生性嗎?

開發 前端
Spring Framework? 每個版本的具體實現會有差異,阿粉使用的版本是 5.3.24 ,所以如果小伙伴看到自己的代碼追蹤的效果跟阿粉的不一樣也不會奇怪,可能是因為版本不一樣而已,不過本質上都是一樣的。

對于 @Component? 注解在日常的工作中相信很多小伙伴都會使用到,作為一種 Spring? 容器托管的通用模式組件,任何被 @Component? 注解標注的組件都會被 Spring 容器掃描。

那么有的小伙伴就要問了,很多時候我們并沒有直接寫 @Component? 注解呀,寫的是類似于 @Service,@RestController,@Configuration? 等注解,不也是一樣可以被掃描到嗎?那這個 @Component 有什么特別的嗎?

元注解

在回答上面的問題之前,我們先來了解一下什么叫元注解,所謂元注解就是指一個能聲明在其他注解上的注解,換句話說就是如果一個注解被標注在其他注解上,那么它就是元注解。

要說明的是這個元注解并不是 Spring? 領域的東西, 而是 Java? 領域的,像 Java? 中的很多注解比如 @Document,@Repeatable? ,@Target 等都屬于元注解。

根據上面的解釋我們可以發現在 Spring? 容器里 @Component 

圖片

Configuration

圖片

controller

@Component 的派生性

通過上面的內容我們是不是可以猜測一下那就是 @Component? 注解的特性被"繼承"下來了?這就可以解釋為什么我們可以直接寫@Service,@RestController? 注解也是可以被掃描到的。但是由于 Java 的注解是不支持繼承的,比如你想通過下面的方式來實現注解的繼承是不合法的。

圖片

@interface

為了驗證我們的猜想,可以通過跟蹤源代碼來驗證一下,我們的目的是研究為什么不直接使用 @Component? 注解也能被 Spring? 掃描到,換句話說就是使用 @Service? 和 @RestController? 的注解也能成為 Spring Bean。

那我們很自然的就可以想到,在掃描的時候一定是根據注解來進行了判斷是否要初始化成 Spring Bean 的。我們只要找到了判斷條件就可以解決我們的疑惑了。

由于 SpringBoot? 項目是通過 main? 方法進行啟動的,調試起來還是很方便的,阿粉這邊準備了一個簡單的 SpringBoot? 工程,里面除了啟動類之外只有一個DemoController.java 代碼如下

package com.example.demojar.controller;

import org.springframework.web.bind.annotation.RestController;

@RestController
public class DemoController {
}

啟動類如下

package com.example.demojar;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.WebApplicationType;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.context.ConfigurableApplicationContext;

@SpringBootApplication(scanBasePackages = {"com.example.demojar"})
public class DemoJarApplication {

public static void main(String[] args){
SpringApplication.run(DemoJarApplication.class, args);
}
}

Debug run? 方法,我們可以定位到 org.springframework.boot.SpringApplication#run(java.lang.String...) ?方法,該方法里面會初始化 SpringBoot? 上下文 context。

context = createApplicationContext();

默認情況下會進到下面的方法,并創建 AnnotationConfigServletWebServerApplicationContext? 并且其構造函數中構造了 ClassPathBeanDefinitionScanner 類路徑 Bean 掃描器。此處已經越來越接近掃描相關的內容了。

org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext.Factory#create

圖片

圖片

圖片

context? 上下文創建完成過后,接下來我們我們會接入到 org.springframework.context.support.AbstractApplicationContext#refresh?,再到 org.springframework.context.support.AbstractApplicationContext#invokeBeanFactoryPostProcessors

org.springframework.context.annotation.ConfigurationClassPostProcessor#postProcessBeanDefinitionRegistry

org.springframework.context.annotation.ConfigurationClassPostProcessor#processConfigBeanDefinitions

經過上面的步驟,最終可以可以定位到掃描的代碼在下面的方法 org.springframework.context.annotation.ComponentScanAnnotationParser#parse? 里面,調用前面上下文初始化的掃描器的 org.springframework.context.annotation.ClassPathBeanDefinitionScanner#doScan 方法,

圖片

圖片

到這里我們已經定位到了掃描具體包路徑的方法,這個方法里面主要看 findCandidateComponents(basePackage); 方法的內容,這個方法就是返回合法的候選組件。說明這個方法會最終返回需要被注冊成 Spring Bean 的候選組件,那我們重點就要看這個方法的實現。

跟蹤這個方法 org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider#findCandidateComponents? 進去我們可以看到通過加進類路徑里面的資源文件,然后再根據資源文件生成 MetadataReader? 對象,最后判斷這個 MetadataReader? 對象是否滿足候選組件的條件,如果滿足就添加到 Set 集合中進行返回。

圖片

繼續追蹤源碼我們可以找到具體的判斷方法在 org.springframework.core.type.filter.AnnotationTypeFilter#matchSelf? 方法中,如下所示,可以看到這里對 MetadataReader? 對象進行了判斷是否有元注解 @Component?。在調試的時候我們會發現 DemoController? 在此處會返回 true?,并且該 MetadataReader? 對象里面還有多個 mappings? ,其實這些 mappings? 對應的就是 Spring 的注解。

圖片

圖片

圖片

這個 mappings? 里面的注解確實包含了 @Component? 注解,因此會返回 true?。那么接下來問題就轉換成,我們的 DemoController? 對應的 MetadataReader 對象是如何創建的。

我們看回到 org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider#scanCandidateComponents? 方法,看看具體 MetadataReader 對象是如何創建的,MetadataReader metadataReader = getMetadataReaderFactory().getMetadataReader(resource);

圖片

圖片

通過構造方法 org.springframework.core.type.classreading.SimpleMetadataReader#SimpleMetadataReader? 進行 MetadataReader?  對象的創建,org.springframework.core.type.classreading.SimpleAnnotationMetadataReadingVisitor#visitEnd?,最終定位到 org.springframework.core.annotation.MergedAnnotationsCollection#MergedAnnotationsCollection? 這里進行 mappings 賦值。

圖片

繼續定位到 org.springframework.core.annotation.AnnotationTypeMappings.Cache#createMappings,org.springframework.core.annotation.AnnotationTypeMappings#addAllMappings,addAllmappings? 方法,內部使用了一個 while? 循環和 Deque? 來循環查詢元注解進行賦值,代碼如下所示,重點是這一行 Annotation[] metaAnnotations = AnnotationsScanner.getDeclaredAnnotations(source.getAnnotationType(), false);

private void addAllMappings(Class<? extends Annotation> annotationType,
Set<Class<? extends Annotation>> visitedAnnotationTypes){

Deque<AnnotationTypeMapping> queue = new ArrayDeque<>();
addIfPossible(queue, null, annotationType, null, visitedAnnotationTypes);
while (!queue.isEmpty()) {
AnnotationTypeMapping mapping = queue.removeFirst();
this.mappings.add(mapping);
addMetaAnnotationsToQueue(queue, mapping);
}
}

private void addMetaAnnotationsToQueue(Deque<AnnotationTypeMapping> queue, AnnotationTypeMapping source){
Annotation[] metaAnnotations = AnnotationsScanner.getDeclaredAnnotations(source.getAnnotationType(), false);
for (Annotation metaAnnotation : metaAnnotations) {
if (!isMappable(source, metaAnnotation)) {
continue;
}
Annotation[] repeatedAnnotations = this.repeatableContainers.findRepeatedAnnotations(metaAnnotation);
if (repeatedAnnotations != null) {
for (Annotation repeatedAnnotation : repeatedAnnotations) {
if (!isMappable(source, repeatedAnnotation)) {
continue;
}
addIfPossible(queue, source, repeatedAnnotation);
}
}
else {
addIfPossible(queue, source, metaAnnotation);
}
}
}

綜上所述我們可以發現盡管我們沒有直接寫 @Component? 注解,只要我們加了類似于 @Service,@RestController? 等注解也是可以成功被 Spring? 掃描到注冊成 Spring Bean? 的,本質的原因是因為這些注解底層都使用了 @Component? 作為元注解,經過源碼分析我們發現了只要有 @Component 元注解標注的注解類也是同樣會被進行掃描的。

總結

上面的源碼追蹤過程可能會比較枯燥和繁瑣,最后我們來簡單總結一下上面的內容:

  • 方法org.springframework.boot.SpringApplication#run(java.lang.String...) ?中進行 Spring 上下文的創建;
  • 在初始化上下文的時候會創建掃描器ClassPathBeanDefinitionScanner;
  • 在org.springframework.context.support.AbstractApplicationContext#refresh? 進行 beanFactory 準備;
  • org.springframework.context.annotation.ClassPathBeanDefinitionScanner#doScan 進行資源掃描
  • 在org.springframework.core.annotation.MergedAnnotationsCollection#MergedAnnotationsCollection? 進行注解 mappings 的賦值;
  • org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider#scanCandidateComponents 方法中進行候選組件的判斷;

上面追蹤的過程可能會比較復雜,但是只要我們理解了原理還是可以慢慢跟上的,因為我們只要把握好了方向,知道首先肯定會進行資源掃描,掃描完了肯定是根據注解之間的關系進行判斷,最終得到我們需要的候選組件集合。至于如何創建 MetadataReader 和如何獲取元注解,只要我們一步步看下去就是可以找到的。

最后說明一下,Spring Framework? 每個版本的具體實現會有差異,阿粉使用的版本是 5.3.24 ,所以如果小伙伴看到自己的代碼追蹤的效果跟阿粉的不一樣也不會奇怪,可能是因為版本不一樣而已,不過本質上都是一樣的。

責任編輯:武曉燕 來源: Java極客技術
相關推薦

2022-09-28 18:16:34

JavaJDK

2015-12-01 13:33:51

UnikernelLinux運維

2023-12-20 08:23:53

NIO組件非阻塞

2021-11-12 05:59:23

容災備份5G

2016-09-29 15:43:33

2022-11-28 00:04:17

2024-01-15 12:16:37

2020-09-03 06:42:12

線程安全CPU

2021-11-09 09:39:21

路由器硬件設備網絡

2024-07-30 08:22:47

API前端網關

2024-11-08 09:48:38

異步編程I/O密集

2019-03-14 12:39:55

安全云計算深信服

2024-07-01 08:40:18

tokio派生線程

2023-06-30 08:26:24

Java注解Java程序元素

2024-03-19 08:01:54

服務熔斷軟件設計模式微服務

2024-02-19 07:44:52

虛擬機Java平臺

2023-07-11 00:12:05

2024-06-27 10:51:28

生成式AI領域

2024-06-11 09:02:30

2023-01-04 11:39:45

點贊
收藏

51CTO技術棧公眾號

免费国产a级片| 福利一区福利二区微拍刺激| 伊人一区二区三区久久精品| 欧美一区二区三区四区夜夜大片| 亚洲av成人无码一二三在线观看| 天堂av最新在线| 一区二区三区四区五区在线 | 亚洲天堂av一区二区三区| 亚洲av无码专区在线| 深爱激情综合网| 欧美在线观看视频一区二区三区| 91在线中文字幕| www.美色吧.com| 毛片在线免费| 中文在线播放一区二区| 亚洲午夜日本在线观看| 国产精品吊钟奶在线| 深夜视频在线观看| 黄色大片在线看| 久久国产综合精品| 美女久久久久久久久久久| 免费看又黄又无码的网站| 麻豆精品久久久久久久99蜜桃| www欧美在线观看| 久久精品男人天堂av| 色综合老司机第九色激情| 精品这里只有精品| 精品99又大又爽又硬少妇毛片| 美腿丝袜亚洲三区| 精品久久五月天| 热这里只有精品| 日本韩国欧美中文字幕| 高清一区二区中文字幕| 久久久精品影视| 久久精品视频在线| 男人添女荫道口喷水视频| 中文字幕日韩免费| 免费看日本一区二区| 欧美精品第1页| 91免费视频网站在线观看| 成人性生生活性生交12| 91网在线播放| 亚洲男女自偷自拍| 日韩三级视频中文字幕| 欧美一区二区三区爽大粗免费| 国产在线欧美日韩| 日韩小视频网站| 在线观看免费高清视频| 国产99久久精品一区二区300| 7777精品久久久大香线蕉| 国产视频观看一区| 国产艳妇疯狂做爰视频| 巨胸喷奶水www久久久| 亚洲综合视频网| 亚洲精品在线观看免费| 午夜av免费观看| 亚洲福利精品| 亚洲激情成人网| 国产精品一区二区免费在线观看| а天堂中文在线官网| 久久综合九色综合久久久精品综合| 91亚洲精品一区| 欧美做受高潮6| 婷婷午夜社区一区| 不卡的av电影| 91嫩草免费看| 亚洲图片在线播放| 视频一区中文字幕国产| 国产一区二区三区视频免费| 无码任你躁久久久久久老妇| 中文字幕一区二区三区四区久久| 欧美一区在线视频| 91视频成人免费| 999久久久久| 免费国产亚洲视频| 国产精品91久久| 天天干天天色综合| 老司机午夜免费精品视频| 国产精品r级在线| 一级片在线观看免费| 日日夜夜精品视频天天综合网| 欧美伊人久久久久久久久影院 | 狠狠入ady亚洲精品| 国产一级淫片久久久片a级| 国产日韩一区欧美| 亚洲成av人片一区二区梦乃| 久久电影天堂| 国产不卡视频一区二区三区| 操91在线视频| 国产午夜手机精彩视频| 欧美日韩日本国产亚洲在线| 精品视频123区在线观看| 国风产精品一区二区| 在线观看中文| 天天av天天翘天天综合网色鬼国产| 久久这里只有精品23| 囯产精品久久久久久| 日韩精品电影在线| 国产精品吹潮在线观看| 91美女精品网站| 国产福利一区在线| 九色91视频| 欧美伦理影视网| 国产精品色噜噜| 欧美日韩午夜爽爽| 成人av影院在线观看| 五月天激情小说综合| 久久久久久久久久久久91| av影视在线看| 亚洲国产精品一区二区尤物区| 成年人午夜视频在线观看| 伊人成综合网站| 欧美日韩视频在线第一区| 91亚洲一区二区| 欧美人妖在线观看| 日韩中文字幕视频在线观看| 亚洲少妇中文字幕| 蜜桃国内精品久久久久软件9| 日韩在线观看免费全集电视剧网站 | a免费在线观看| 精品国产乱码久久久久久虫虫漫画| 91蝌蚪视频在线观看| 欧美性videos| 亚洲一区二区三区小说| 老熟妇仑乱视频一区二区| 精品国产第一国产综合精品| 国产视频在线观看一区二区| 国产精品久久免费观看| 国内自拍视频网| 色噜噜一区二区| 国外成人免费在线播放| 日韩欧美成人午夜| 在线成人h网| 视频欧美精品| 一色桃子av在线| 97超视频在线观看| 精品国产91久久久久久浪潮蜜月| 在线观看亚洲视频| 欧美成人三级视频| 日韩中文在线| 国产亚洲欧洲高清| 国产一级视频在线观看| 欧美日韩国产高清| 国产成人精品久久| 人人妻人人玩人人澡人人爽| 伊人色综合久久天天| 五月天av在线播放| 成人亚洲免费| 91福利国产成人精品照片| 国产一二三在线视频| 成人在线观看免费视频| 日韩av在线一区| 69av视频在线| 久久精品av麻豆的观看方式| 日本不卡久久| 亚洲v.com| 亚洲国产精品系列| jizz亚洲少妇| 久久精品理论片| 精品亚洲第一| 成人免费图片免费观看| 国产精品福利在线播放| 乱子伦视频在线看| 中文字幕免费视频| 被黑人猛躁10次高潮视频| 影音先锋亚洲视频| 激情五月综合色婷婷一区二区| 国产精品观看在线亚洲人成网| 欧美伦理91i| 国产视频一区在线| 精品国产一区久久| 久久综合伊人77777| 粉嫩av懂色av蜜臀av分享| 午夜欧美视频| 日韩福利在线播放| 不卡的免费av| 国产成人精品一区二区三区网站观看| www.-级毛片线天内射视视| 免费污视频在线一区| 日韩成人在线视频观看| 91精品国产乱码久久久张津瑜| 99久精品国产| 久久天堂国产精品| freexxx性亚洲精品| 亚洲成人aaa| 国精产品视频一二二区| 美日韩一区二区| 热这里只有精品| 北条麻妃一区二区三区在线观看 | 天天影院图片亚洲| 久久久综合视频| 国产天堂在线播放| jizzjizz欧美69巨大| 国产精品亚洲片夜色在线| 免费在线看黄网站| 日韩精品影音先锋| 国产污片在线观看| 国产亚洲精品bt天堂精选| xxxx在线免费观看| 99在线热播精品免费99热| 另类欧美小说| 欧美电影在线观看网站| 色综合久久久久久中文网| 九色视频在线观看免费播放| 国产一区二区三区成人欧美日韩在线观看 | 国产精品videosex性欧美| 成人vr资源| 日韩欧美中字| 韩日欧美一区| 卡一卡二国产精品| 国产一区二区免费在线| 久久久久9999亚洲精品| 分分操这里只有精品| 日韩高清影视在线观看| 国产va免费精品高清在线| freemovies性欧美| 国产激情一区| 欧美成人免费全部网站| 精品国产亚洲一区二区三区在线 | www亚洲欧美| 精品乱码亚洲一区二区不卡| 亚洲国产精品久久91精品| 国产一区二区三区欧美| 久久国产精彩视频| 日韩av电影在线播放| 51国偷自产一区二区三区的来源| 国产精品jizz在线观看老狼| 国产精品三级一区二区| 一本色道久久综合亚洲二区三区| 日韩电影在线观看永久视频免费网站| 亚洲欧美日韩精品久久奇米色影视 | 一区二区三区四区av| 国内性生活视频| 四季av在线一区二区三区| 国产精品日韩高清| 国精品产品一区| 国产成人精品电影久久久| 黑森林国产精品av| 欧美成人免费网| 国产午夜视频在线观看| 国产精品亲子乱子伦xxxx裸| 精品无码av一区二区三区| 国产一区二区按摩在线观看| 国产一级片自拍| 丝袜美腿亚洲一区二区图片| 97在线国产视频| 欧美在线首页| 在线看无码的免费网站| 欧美激情久久久久久久久久久| 成人精品一区二区三区电影免费| gogo亚洲高清大胆美女人体| 久久99久久99精品免观看粉嫩| 888av在线| 国产一区二区激情| 五月激情婷婷综合| 欧美mv日韩mv| 亚洲精品网站在线| 精品国产人成亚洲区| 性生活免费网站| 欧美一区二区三区性视频| 亚洲天堂手机版| 欧美综合一区二区| 中文字幕在线观看视频免费| 欧美亚洲一区三区| 国产乡下妇女做爰视频| 洋洋成人永久网站入口| 欧美黄片一区二区三区| 亚洲免费观看高清完整| 国产黄色小视频网站| 国产精品福利一区二区三区| 三级影片在线看| 亚洲人一二三区| 欧美体内she精高潮| 国产福利一区二区三区视频在线| 四虎成人在线播放| 国产99久久久国产精品免费看| 亚洲av成人片无码| 久久久三级国产网站| 国产精品美女高潮无套| 91色porny在线视频| 成人在线一级片| 日本一区二区三区视频视频| 日本成人免费在线观看| 亚洲欧美国产高清| 国产在线视频卡一卡二| 一本大道综合伊人精品热热| 在线观看国产成人| 日韩欧美视频一区| 娇妻被老王脔到高潮失禁视频| 黄视频在线观看网站| 欧美va日韩va| 国产77777| 亚洲人成电影网站色www| 国产免费视频在线| 免费av一区二区| 都市激情国产精品| 欧洲亚洲在线视频| 91精品一久久香蕉国产线看观看 | 欧美日韩成人综合在线一区二区| 卡一卡二卡三在线观看| 欧美激情在线观看视频免费| 91视频免费在线看| 精品久久久久久久久久久| 日韩欧美国产另类| 精品少妇一区二区三区在线播放 | 欧美丝袜丝nylons| 国产又粗又大又黄| 日韩av综合网| aiai在线| 欧美亚洲成人网| 羞羞视频在线观看一区二区| 国产成人精品福利一区二区三区 | 欧美三级免费观看| 日韩欧美一区二区在线观看| 日韩女优在线视频| www视频在线观看免费| 99久久婷婷国产综合精品青牛牛| 国产在线播放一区三区四| 亚洲va欧美va人人爽午夜| 日韩欧美区一区二| 国产精品青草久久久久福利99| 无码少妇一区二区三区芒果| 国产美女福利在线观看| 性欧美办公室18xxxxhd| 国产精品亚洲d| 国产精品swag| 色综合五月天| 奇米精品一区二区三区| 精一区二区三区| 水蜜桃一区二区| 欧美独立站高清久久| 国产午夜福利100集发布| 理论电影国产精品| 亚洲黄色在线网站| 亚洲美女免费在线| 中文字幕免费在线看| 欧洲一区二区三区在线| www.激情五月| 日韩中文字幕视频在线| av有声小说一区二区三区| 国产成人精品日本亚洲11 | 亚洲一区二区三区中文字幕| 8090成年在线看片午夜| 亚洲久久中文字幕| 日本美女在线中文版| 欧美7777| 国产女主播一区| 欧美一级片免费在线| 91插插插影院| 欧美wwww| 欧美成人激情在线| 99久久亚洲国产日韩美女| 久久久久网址| 激情欧美丁香| 欧美日韩一区二区区| 中文字幕亚洲电影| 97超碰人人草| 久久6免费高清热精品| 成午夜精品一区二区三区软件| 日韩视频一二三| 成人网页在线观看| 一区二区三区四区毛片| 国产精品色哟哟| 99久久免费国产精精品| 欧美精品一区三区| 9l亚洲国产成人精品一区二三 | 97香蕉超级碰碰久久免费的优势| 女同另类激情重口| 日本在线视频www| 国产精品美女久久久久aⅴ| 国产免费黄色大片| 欧美激情精品久久久久久久变态| 欧美福利在线播放网址导航| 欧美精品一区免费| 久久精品一区八戒影视| 一本色道久久综合精品婷婷| 九九热这里只有精品免费看| 国产精品极品在线观看| 无遮挡又爽又刺激的视频| 欧美极品aⅴ影院| 国产精品久久久久久无人区| 亚洲第一男人天堂| 麻豆蜜桃在线观看| 亚洲v欧美v另类v综合v日韩v| 国产在线精品一区二区夜色| 亚洲精品77777| 色悠悠久久久久| 亚洲乱码精品久久久久..| 国产欧美精品区一区二区三区| 日韩伦人妻无码| 伊人伊成久久人综合网小说| 欧美日韩黄网站| 免费观看日韩毛片| 国产精品国产成人国产三级 | 久久久久久久久久久一区| 卡一卡二国产精品| 91美女免费看| 久久综合88中文色鬼| 欧美在线导航| 古装做爰无遮挡三级聊斋艳谭|