最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Spring?IOC中的組件掃描

 更新時(shí)間:2024年04月30日 09:55:41   作者:紙杯沒茶  
通過自動(dòng)掃描,Spring?會(huì)自動(dòng)從掃描指定的包及其子包下的所有類,并根據(jù)類上的特定注解將該類裝配到容器中,而無需在?XML?配置文件或?Java?配置類中逐一聲明每一個(gè)?Bean,這篇文章主要介紹了Spring?IOC中的組件掃描,需要的朋友可以參考下

版本 Spring Framework 6.0.9?

1. 前言

通過自動(dòng)掃描,Spring 會(huì)自動(dòng)從掃描指定的包及其子包下的所有類,并根據(jù)類上的特定注解將該類裝配到容器中,而無需在 XML 配置文件或 Java 配置類中逐一聲明每一個(gè) Bean。

支持的注解
Spring 支持一系列注解,用于標(biāo)記哪些類應(yīng)被自動(dòng)掃描并作為 Bean 管理。這些注解通常包含:

  • @Component:基礎(chǔ)注解,標(biāo)記一個(gè)類作為 Spring 組件。所有其他特殊用途的組件注解都繼承自此注解。
  • @Repository:用于標(biāo)注 DAO(Data Access Object)類,除了具備 @Component 的功能外,還為數(shù)據(jù)訪問異常提供了特殊的翻譯機(jī)制。
  • @Service:用于標(biāo)注業(yè)務(wù)層(Service)類,強(qiáng)調(diào)這是一個(gè)業(yè)務(wù)相關(guān)的組件。
  • @Controller:用于標(biāo)注 MVC 架構(gòu)中的控制器類,通常在 Spring MVC 中使用,與 Spring Web 相關(guān)的請(qǐng)求處理邏輯相關(guān)聯(lián)。
  • @Configuration:用于標(biāo)注配置類,這類類通常包含 @Bean 方法,用于定義其他 Bean。
  • @RestController:結(jié)合了 @Controller 和 @ResponseBody,適用于構(gòu)建 RESTful Web 服務(wù)的控制器。

例子相關(guān)實(shí)體類

控制層(例子中沒引入spring-web包,注解先使用@Component替代)

服務(wù)層

數(shù)據(jù)訪問層

2. 基于xml

2.1 使用

在 Spring 的XML配置文件中,通過 <context:component-scan> 標(biāo)簽開啟自動(dòng)掃描功能。我們可以配置 base-package 指定掃描路徑。

輸出信息說明每個(gè)實(shí)體類都已加載到容器。

<context:component-scan> 其他配置元素:

  • resource-pattern:可選屬性,用于指定在掃描包路徑下應(yīng)匹配的資源模式。默認(rèn)值為 “**/*.class”,即掃描所有 .class 文件??梢愿鶕?jù)需要修改此模式,例如,僅掃描特定目錄下的類。
  • use-default-filters:布爾屬性,默認(rèn)值為 true。決定是否啟用默認(rèn)的過濾規(guī)則,即查找?guī)в?@Component、@Repository、@Service、@Controller、@Configuration 等注解的類。如果設(shè)置為 false,則需要手動(dòng)配置 和 來指定掃描規(guī)則。
  • scope-resolver:指定一個(gè)自定義的 ScopeMetadataResolver 實(shí)現(xiàn)類,用于確定掃描到的 Bean 的作用域。默認(rèn)情況下,Spring 使用 AnnotationScopeMetadataResolver,根據(jù)類上的 @Scope 注解來確定作用域。
  • scoped-proxy:指定是否為掃描到的帶有作用域注解的 Bean 創(chuàng)建代理。可能的值包括:
    • no(默認(rèn)):不創(chuàng)建代理。
    • interfaces:為實(shí)現(xiàn)了接口的 Bean 創(chuàng)建 JDK 動(dòng)態(tài)代理。
    • targetClass:為未實(shí)現(xiàn)接口或需要保留原始類類型的 Bean 創(chuàng)建 CGLIB 代理。
  • name-generator:指定一個(gè)自定義的 BeanNameGenerator 實(shí)現(xiàn)類,用于生成掃描到的 Bean 的名稱。默認(rèn)使用 AnnotationBeanNameGenerator,根據(jù)類上的 @Component 等注解的 value 屬性或類名生成 Bean 名稱。
  • include-filter 和 exclude-filter:這兩個(gè)元素屬于子標(biāo)簽,用于指定更細(xì)粒度的掃描規(guī)則??梢园醋⒔忸愋汀⒆⒔鈱傩?、全類名模式等進(jìn)行包含或排除。

2.2 掃描原理

  • 當(dāng)我們使用ClassPathXmlApplicationContext作為IOC容器,在refresh方法的obtainFreshBeanFactory階段會(huì)創(chuàng)建一個(gè)bean工廠DefaultListableBeanFactory。
  • 當(dāng)前上下文調(diào)用loadBeanDefinitions方法,根據(jù)容器的配置文件加載bean定義。
  • 配置文件中通過 <context:component-scan> 標(biāo)簽開啟自動(dòng)掃描功能,屬于其他命名空間,托管給 ComponentScanBeanDefinitionParser處理。
  • ComponentScanBeanDefinitionParser#parse方法中創(chuàng)建一個(gè)ClassPathBeanDefinitionScanner對(duì)象,調(diào)用其scan方法掃描組件并加載到bean工廠中。

其他命名空間

Spring框架除了核心的XML命名空間外,還提供了多個(gè)擴(kuò)展命名空間(除beans以外的命名空間),以支持特定的功能模塊和簡(jiǎn)化配置。

  • http://www.springframework.org/schema/beans:核心命名空間,這是最基礎(chǔ)且最常用的命名空間,用于定義bean、設(shè)置屬性、注入依賴、配置構(gòu)造函數(shù)參數(shù)、初始化方法、銷毀方法、自動(dòng)裝配等基本IoC容器功能。http://www.springframework.org/schema/context:
  • context命名空間,提供了對(duì)Java配置類、自動(dòng)掃描、注解驅(qū)動(dòng)的bean定義、屬性占位符替換、資源加載等上下文相關(guān)的高級(jí)功能的支持。通過此命名空間,可以簡(jiǎn)化基于注解的配置,如@Component、@Autowired等。

在實(shí)例化XmlReaderContext時(shí),DefaultBeanDefinitionDocumentReader會(huì)創(chuàng)建一個(gè)命名空間解析器DefaultNamespaceHandlerResolver,緩存到XmlReaderContext,當(dāng)Reader解析配置文件時(shí)發(fā)現(xiàn)存在其他命名空間時(shí),通過DefaultNamespaceHandlerResolver加載 META-INF/spring.handlers 路徑下的其他命名空間處理器,獲取對(duì)應(yīng)的處理器處理。

XmlReaderContext 是Spring框架中用于處理XML配置文件解析過程中的上下文對(duì)象,為DefaultBeanDefinitionDocumentReader在解析和處理XML配置文件時(shí)提供了必要的環(huán)境支持。

context命名空間處理器(ComponentScanBeanDefinitionParser)

  • 獲取基礎(chǔ)包名basePackages。
  • 創(chuàng)建類路徑 Bean 定義掃描程序ClassPathBeanDefinitionScanner。
  • 遍歷掃描包名,查找被@Component及其派生注解修飾的類。將它們封裝為BeanDefinitionHolder對(duì)象。
  • 往bean工廠加載特定注解后置處理器的bean定義(internalConfigurationAnnotationProcessor、internalAutowiredAnnotationProcess、internalCommonAnnotationProcessor、internalEventListenerProcessor、internalEventListenerFactory),觸發(fā)組件注冊(cè)事件.

獲取基礎(chǔ)包名basePackages

  • element.getAttribute(BASE_PACKAGE_ATTRIBUTE)方法從對(duì)象中獲取base-package的屬性值。
  • parserContext.getReaderContext().getEnvironment().resolvePlaceholders(basePackage)方法解析占位符,獲取解析值。
  • StringUtils.tokenizeToStringArray(basePackage,ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS)方法將基礎(chǔ)包名按逗號(hào)、分號(hào)或空格等常見分隔符拆分為一個(gè)字符串?dāng)?shù)組basePackages。

創(chuàng)建組件掃描器

ComponentScanBeanDefinitionParser#configureScanner方法通過對(duì)XML元素element的各項(xiàng)屬性(use-default-filters、resource-pattern、name-generator、scope-resolver、scoped-proxy)和子元素(include-filter、exclude-filter)進(jìn)行解析,創(chuàng)建一個(gè)定制化的掃描器ClassPathBeanDefinitionScanner。

另外通過ClassPathBeanDefinitionScanner構(gòu)造函數(shù)實(shí)例化時(shí),會(huì)創(chuàng)建一個(gè)Component類型的注解類型過濾器AnnotationTypeFilter添加到includeFilters屬性中,用于將類與@Component進(jìn)行匹配。

掃描組件

ClassPathBeanDefinitionScanner#doScan掃描指定的basePackages包及其子包,查找并處理符合要求的bean定義,最終將它們封裝為BeanDefinitionHolder對(duì)象并返回,bean定義類型是ScannedGenericBeanDefinition。

掃描核心方法ClassPathScanningCandidateComponentProvider#findCandidateComponents用于在指定的basePackage包及其子包下查找符合要求的候選bean組件(BeanDefinition),支持索引查找(效率更高)或按傳統(tǒng)方式查找(獲取指定包下所有class對(duì)象篩選)。

我們只看傳統(tǒng)方式查找方式,ClassPathScanningCandidateComponentProvider#scanCandidateComponents方法用于在給定的basePackage及其子包下通過類路徑掃描機(jī)制查找候選bean組件(BeanDefinition).

ClassPathScanningCandidateComponentProvider#isCandidateComponent方法用于判斷給定的MetadataReader所代表的類是否滿足候選bean組件的條件,在不添加其他排除過濾器、包含過濾器或配置,上面創(chuàng)建組件掃描器過程中,已知添加了一個(gè)AnnotationTypeFilter包含過濾器,在此處使用,匹配被@Component注解的類。

觸發(fā)組件注冊(cè)事件

ComponentScanBeanDefinitionParser#registerComponents負(fù)責(zé)將一組BeanDefinition注冊(cè)到Spring IoC容器中,并處理與之相關(guān)的XML元素及注解配置處理器。實(shí)際上做了兩件事

往bean工廠加載特定注解后置處理器的bean定義觸發(fā)組件注冊(cè)事件,一般情況下是EmptyReaderEventListener,空方法。

3. 全注解開發(fā)

AnnotationConfigApplicationContext 是 Spring Framework 中的一個(gè)核心類,用于創(chuàng)建和管理基于 Java 注解的 Spring 應(yīng)用程序上下文。AnnotationConfigApplicationContext 有兩種開啟組件掃描的方式

  • 直接指定包路徑
  • 通過@ComponentScan注解

3.1 通過指定包路徑開啟掃描

使用

掃描原理

接受一個(gè)字符串?dāng)?shù)組參數(shù) basePackages的有參構(gòu)造邏輯分成三部分:

  • this(); 調(diào)用無參構(gòu)造函數(shù)
  • scan(basePackages); 執(zhí)行類路徑掃描
  • refresh(); 啟動(dòng)應(yīng)用上下文

無參構(gòu)造函數(shù)實(shí)例化組件掃描器 ClassPathBeanDefinitionScanner,用于在類路徑中掃描并注冊(cè)基于注解的 Bean 定義(如 @Component、@Service、@Repository、@Controller 等)。

調(diào)用ClassPathBeanDefinitionScanner#scan方法掃描組件,與基于xml掃描邏輯一樣,調(diào)用的是ClassPathBeanDefinitionScanner#scan方法,所以bean定義創(chuàng)建的類型也是ScannedGenericBeanDefinition類。

3.2 通過Java配置類開啟掃描

使用

c

掃描原理

接受一個(gè)類型為 Class<?> 的可變參數(shù)數(shù)組 componentClasses的有參構(gòu)造邏輯分成三部分:

  • this(); 調(diào)用無參構(gòu)造函數(shù)
  • register(componentClasses); 注冊(cè)指定的組件
  • refresh(); 啟動(dòng)應(yīng)用上下文

第一部分雖然與接受字符串的有參構(gòu)造(指定掃描路徑)一樣調(diào)用了無參構(gòu)造,但我們這里只關(guān)注 帶注釋的 Bean 定義讀取器AnnotatedBeanDefinitionReader,而不是類路徑 Bean 定義掃描程器ClassPathBeanDefinitionScanner。

實(shí)例化AnnotatedBeanDefinitionReader過程中,會(huì)調(diào)用AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry)方法,往bean工廠注冊(cè)一個(gè)bean定義后置處理器ConfigurationClassPostProcessor。

第二部分注冊(cè)Java配置類ScanConfig,實(shí)例化并初始化bean定義類AnnotatedGenericBeanDefinition,并加載到bean工廠中。

第三部分在refresh方法invokeBeanFactoryPostProcessors階段,會(huì)調(diào)用在第一部分注冊(cè)的ConfigurationClassPostProcessor(在當(dāng)前階段會(huì)調(diào)用getBean方法實(shí)例化)后置處理。

ConfigurationClassPostProcessor 是 Spring 框架中一個(gè)重要的 BeanDefinitionRegistryPostProcessor 實(shí)現(xiàn),主要負(fù)責(zé)處理帶有 @Configuration 注解的類以及它們內(nèi)部定義的 @Bean 方法和其他相關(guān)注解。postProcessBeanDefinitionRegistry方法會(huì)篩選出有效的@configuration類,調(diào)用配置類解析器ConfigurationClassParser的parse方法解析。

從第二部分知道,ScanConfig生成的bean定義類是AnnotatedGenericBeanDefinition,是AnnotatedBeanDefinition的子類。debug源碼到處理@ComponentScan注解(this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName());),說明ConfigurationClassParser處理邏輯委托給componentScanParser,調(diào)用其parse方法處理。

這里的this.componentScanParser是ComponentScanAnnotationParser類,在調(diào)用ConfigurationClassParser構(gòu)造函數(shù)實(shí)例化時(shí)創(chuàng)建。

ComponentScanAnnotationParser#parse方法中的邏輯就很熟悉了,可以對(duì)標(biāo)context命名空間處理各個(gè)屬性。在方法中是新建了一個(gè)ClassPathBeanDefinitionScanner類,而不是使用AnnotationConfigApplicationContext無參構(gòu)造中實(shí)例化的ClassPathBeanDefinitionScanner,最后執(zhí)行doscan方法掃描組件。

總結(jié)

總結(jié)一下通過@ComponentScan開啟掃描流程.

  • this();
    • 在實(shí)例化AnnotatedBeanDefinitionReader過程中,往bean工廠加載了ConfigurationClassPostProcessor的bean定義
  • register(componentClasses);
    • 往bean工廠加載了包含@Configuration、@ComponentScan注解的ScanConfig配置類 的bean定義。
  • refresh();
    • 在invokeBeanFactoryPostProcessors階段實(shí)例化了ConfigurationClassPostProcessor,并調(diào)用其postProcessBeanDefinitionRegistry方法處理@Configuration配置類。
    • ConfigurationClassPostProcessor#postProcessBeanDefinitionRegistry方法中,獲取并篩選有效的 @Configuration類,實(shí)例化了配置類解析器ConfigurationClassParser,調(diào)用其parse方法,解析配置類(ScanConfig.class)。
    • ConfigurationClassParser#parse包含處理配置類中各種注解,其中就包含@ComponentScan。但解析@ComponentScan,委托給了ComponentScanAnnotationParser類,調(diào)用其parse方法.
    • ComponentScanAnnotationParser#parse實(shí)例化了類路徑 Bean 定義掃描器ClassPathBeanDefinitionScanner,ClassPathBeanDefinitionScanner加載掃描配置后調(diào)用doScan掃描組件。

相關(guān)文章

  • freemarker簡(jiǎn)介_動(dòng)力節(jié)點(diǎn)Java學(xué)院整理

    freemarker簡(jiǎn)介_動(dòng)力節(jié)點(diǎn)Java學(xué)院整理

    FreeMarker是一個(gè)模板引擎,一個(gè)基于模板生成文本輸出的通用工具,使用純Java編寫,有興趣的可以了解一下
    2017-08-08
  • Java動(dòng)態(tài)腳本Groovy獲取Bean技巧

    Java動(dòng)態(tài)腳本Groovy獲取Bean技巧

    這篇文章主要給大家分享的是Java動(dòng)態(tài)腳本Groovy獲取Bean技巧,在Java代碼中當(dāng)我們需要一個(gè)Bean對(duì)象,通常會(huì)使用spring中@Autowired注解,用來自動(dòng)裝配對(duì)象。下面我們一起進(jìn)入文章學(xué)習(xí)個(gè)表格多 詳細(xì)內(nèi)容吧

    2021-12-12
  • spring的UnexpectedRollbackException事務(wù)嵌套示例解析

    spring的UnexpectedRollbackException事務(wù)嵌套示例解析

    這篇文章主要為大家介紹了spring的UnexpectedRollbackException事務(wù)嵌套示例解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-09-09
  • springboot連接不同數(shù)據(jù)庫的寫法詳解

    springboot連接不同數(shù)據(jù)庫的寫法詳解

    這篇文章主要介紹了springboot連接不同數(shù)據(jù)庫的寫法?,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2023-04-04
  • hbase訪問方式之java api

    hbase訪問方式之java api

    這篇文章主要介紹了hbase訪問方式之java api,需要的朋友可以參考下
    2017-09-09
  • Java實(shí)現(xiàn)五子棋單機(jī)版

    Java實(shí)現(xiàn)五子棋單機(jī)版

    這篇文章主要為大家詳細(xì)介紹了Java實(shí)現(xiàn)五子棋單機(jī)版,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-05-05
  • 這一次搞懂Spring事務(wù)是如何傳播的

    這一次搞懂Spring事務(wù)是如何傳播的

    這篇文章主要介紹了這一次搞懂Spring事務(wù)是如何傳播的,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧
    2020-08-08
  • Java 獲取 jar包以外的資源操作

    Java 獲取 jar包以外的資源操作

    這篇文章主要介紹了Java 獲取 jar包以外的資源操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧
    2020-08-08
  • springboot下配置多數(shù)據(jù)源的方法

    springboot下配置多數(shù)據(jù)源的方法

    本篇文章主要介紹了springboot下配置多數(shù)據(jù)源的方法,具有一定的參考價(jià)值,有興趣的可以了解一下
    2017-04-04
  • PowerJob的DispatchStrategy方法工作流程源碼解讀

    PowerJob的DispatchStrategy方法工作流程源碼解讀

    這篇文章主要為大家介紹了PowerJob的DispatchStrategy方法工作流程源碼解讀,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2024-01-01

最新評(píng)論

哈密市| 怀安县| 田林县| 海林市| 东丽区| 大同县| 林甸县| 永顺县| 桃园县| 岳阳县| 宁城县| 江孜县| 宁阳县| 额敏县| 尤溪县| 中山市| 报价| 台湾省| 桃江县| 都兰县| 南安市| 定陶县| 囊谦县| 钟山县| 福州市| 潮州市| 朝阳市| 正镶白旗| 孝感市| 凤翔县| 永新县| 嘉禾县| 铁岭市| 井研县| 确山县| 元江| 米泉市| 波密县| 吴川市| 禹州市| 巴楚县|