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

Spring創(chuàng)建BeanDefinition之路徑掃描詳解

 更新時間:2025年04月07日 09:50:26   作者:程序員俠客行  
這篇文章主要介紹了Spring創(chuàng)建BeanDefinition之路徑掃描方式,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教

一、從示例開始

當(dāng)我們創(chuàng)建AnnotationConfigApplicationContext對象時,Spring底層到底做了些什么?

來看下面示例。

package com.xiakexing;

import com.xiakexing.service.UserService;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class Test {

	public static void main(String[] args) {
		AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
		UserService userService = context.getBean("userService", UserService.class);
		userService.test();
    }
}
package com.xiakexing;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

@Configuration
@ComponentScan(value = "com.xiakexing")
public class AppConfig {

}
package com.xiakexing.service;

import org.springframework.stereotype.Component;

@Component
public class UserService {

    public void test() {
        System.out.println("hello spring");
    }
}

我們猜測這幾行代碼執(zhí)行邏輯:

  • new AnnotationConfigApplicationContext(AppConfig.class)時,從AppConfig類解析掃描路徑即@ComponentScan;
  • 遍歷掃描路徑下的所有Java類,如果某個類上有@Component、@Service等注解,Spring就為這個類創(chuàng)建BeanDefinition,保存到Map中,比如Map<String, Class>,key是根據(jù)規(guī)則生成的beanName,value就是當(dāng)前類的class對象。
  • context.getBean("userService")時,Spring根據(jù)beanName找到類的class對象,反射調(diào)用構(gòu)造器創(chuàng)建對象。

帶著上面的猜想,我們來看看源碼。本文暫且關(guān)注路徑掃描的實現(xiàn),隨后的文章將講解BeanDefinition的創(chuàng)建過程。

二、創(chuàng)建AnnotationConfigApplicationContext

構(gòu)造方法的入?yún)⑹莄omponentClasses,即可以傳入多個配置類。

this()中創(chuàng)建了AnnotatedBeanDefinitionReader、ClassPathBeanDefinitionScanner,將用于掃描指定路徑下的類,創(chuàng)建BeanDefinition。

JFR 是 Java Flight Record (Java飛行記錄),是JVM 內(nèi)置的基于事件的JDK監(jiān)控記錄框架。StartupStep是Spring基于JFR對運行過程的監(jiān)控,閱讀源碼時可忽略它。

注意,AnnotationConfigApplicationContext間接實現(xiàn)了BeanDefinitionRegistry接口,具備向容器中注冊BeanDefinition的能力。

在創(chuàng)建ClassPathBeanDefinitionScanner對象時,指定了使用DefaultFilters:將掃描所有帶有@Component注解的類。

總結(jié):this()僅僅實例化了容器對象,創(chuàng)建了Reader、Scanner,用于解析類信息。

三、注冊Configuration類

3.1 創(chuàng)建BeanDefinition

register(componentClasses),顯然是將配置類注冊到容器中。

來看AnnotatedBeanDefinitionReader#doRegisterBean的核心邏輯:

  • 為配置類創(chuàng)建AnnotatedGenericBeanDefinition對象;
  • 處理@Conditional,如果條件不滿足,將舍棄這個類;
  • 給BeanDefinition對象屬性賦值;
  • 生成beanName,解析@Lazy、@Primary、@DependsOn等注解;
  • 創(chuàng)建BeanDefinitionHolder對象,發(fā)起注冊。

3.2 注冊BeanDefinition

BeanDefinitionHolder類只是對BeanDefinition的包裝,僅有三個屬性:beanDefinition、beanName和aliases。

在BeanDefinitionReaderUtils#registerBeanDefinition中

最終會調(diào)用DefaultListableBeanFactory#registerBeanDefinition方法,執(zhí)行這幾行代碼:

看到了BeanFactory的兩個核心數(shù)據(jù)結(jié)構(gòu):

  • beanDefinitionMap保存了beanName與beanDefinition的映射;
  • beanDefinitionNames保存了所有的beanName

果然與我們當(dāng)初的猜想一致。

至此,配置類已被添加到beanDefinitionMap中,可是@ComponentScan指定的包路徑,在哪兒被處理了呢?

四、掃描包路徑

先說結(jié)論:@ComponentScan包路徑下的類,是在ClassPathBeanDefinitionScanner#scan中被處理的。

來看AnnotationConfigApplicationContext的另一個構(gòu)造方法:入?yún)⒕褪侵付ò窂健?/p>

轉(zhuǎn)調(diào)到ClassPathBeanDefinitionScanner#scan。

基于配置類創(chuàng)建AnnotationConfigApplicationContext時,是在哪兒調(diào)了scan()或doScan()呢?答案就在refresh()中。

4.1 BeanFactoryPostProcessor接口

先看類注釋:

Factory hook that allows for custom modification of an application context's bean definitions, adapting the bean property values of the context's underlying bean factory.

工廠鉤子,允許自定義修改應(yīng)用程序上下文的bean定義,調(diào)整上下文的底層bean工廠的bean屬性值。

A BeanFactoryPostProcessor may interact with and modify bean definitions, but never bean instances.

BeanFactoryPostProcessor可以與bean定義交互和修改,但不能與bean實例交互。

可見,該接口是BeanFactory的后置處理器,在創(chuàng)建Bean實例前,干涉BeanDefinition創(chuàng)建和更新。

僅有一個方法:

void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException;

該接口有個重要的子接口BeanDefinitionRegistryPostProcessor,能夠向容器注冊更多的BeanDefinition。

Extension to the standard BeanFactoryPostProcessor SPI, allowing for the registration of further bean definitions before regular BeanFactoryPostProcessor detection kicks in.

對標(biāo)準(zhǔn)BeanFactoryPostProcessor SPI的擴展,允許在常規(guī)BeanFactoryPostProcessor檢測開始之前注冊進一步的bean定義。

4.2 ConfigurationClassPostProcessor類

源碼中,BeanDefinitionRegistryPostProcessor接口僅有唯一實現(xiàn)ConfigurationClassPostProcessor。

在ConfigurationClassPostProcessor#processConfigBeanDefinitions中,

檢查已注冊的每一個BeanDefinition,是否是候選配置類(或組件),滿足以下任意條件即可:

  • 類上有@Configuration注解;
  • 類上有以下任意一個注解;

  • 類中有@Bean注解的方法;

得到Set<BeanDefinitionHolder> candidates后,會調(diào)用ConfigurationClassParser.parse()

接下來會遍歷處理每一個候選類

在ConfigurationClassParser#doProcessConfigurationClass中,解析@ComponentScan、@ComponentScans注解;

  • 執(zhí)行Filter邏輯后,得到basePackages路徑集;
  • 調(diào)用ClassPathBeanDefinitionScanner#doScan,為路徑下的Bean創(chuàng)建BeanDefinition,并注冊到容器中。

關(guān)于doScan方法的詳細(xì)邏輯,我們下一篇再看。

五、邏輯閉環(huán)

要用ConfigurationClassPostProcessor來處理配置類,Spring容器中就得先有該類的實例。那么,這個類是何時注冊到容器中的?

答案就在new AnnotatedBeanDefinitionReader(this)中:

為ConfigurationClassPostProcessor創(chuàng)建BeanDefinition并注冊。

當(dāng)執(zhí)行AbstractApplicationContext#refresh時,其中有一步是調(diào)用容器中BeanFactoryPostProcessor接口所有實現(xiàn)。

此時,ConfigurationClassPostProcessor#postProcessBeanDefinitionRegistry將被執(zhí)行。

流程圖

總結(jié)

以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。

相關(guān)文章

  • SpringBoot配置HTTPS的詳細(xì)步驟

    SpringBoot配置HTTPS的詳細(xì)步驟

    本文介紹了配置SpringBoot項目HTTPS的全流程,包括開發(fā)環(huán)境生成自簽名證書和生產(chǎn)環(huán)境配置正式SSL證書,以及配置HTTP自動跳轉(zhuǎn)HTTPS以提升用戶體驗,注意事項和常見問題也一并進行了說明,需要的朋友可以參考下
    2026-03-03
  • SpringBoot解析自定義yml文件的流程步驟

    SpringBoot解析自定義yml文件的流程步驟

    這篇文章主要介紹了SpringBoot解析自定義yml文件的流程步驟,文章通過代碼示例和圖文結(jié)合的方式給大家介紹的非常詳細(xì), 對大家的學(xué)習(xí)或工作有一定的幫助,需要的朋友可以參考下
    2024-06-06
  • SpringBoot打包前重新拉取maven依賴的方法實現(xiàn)

    SpringBoot打包前重新拉取maven依賴的方法實現(xiàn)

    在使用 Maven 構(gòu)建 Spring Boot 項目時,如果希望在每次打包時都強制拉取依賴,可以通過以下方法實現(xiàn),本文給大家介紹了四種實現(xiàn)方法,并通過代碼講解的非常詳細(xì),需要的朋友可以參考下
    2024-12-12
  • org.apache.ibatis.annotations不存在的問題

    org.apache.ibatis.annotations不存在的問題

    這篇文章主要介紹了org.apache.ibatis.annotations不存在的問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-10-10
  • SSM項目實現(xiàn)短信驗證碼登錄功能的示例代碼

    SSM項目實現(xiàn)短信驗證碼登錄功能的示例代碼

    這篇文章主要為大家分享了在SSM項目中實現(xiàn)短信驗證碼登錄功能的示例代碼,文中的實現(xiàn)步驟講解詳細(xì),感興趣的小伙伴可以跟隨小編一起動手嘗試一下
    2022-05-05
  • java實現(xiàn)投票程序設(shè)計

    java實現(xiàn)投票程序設(shè)計

    這篇文章主要介紹了java實現(xiàn)投票程序設(shè)計,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2015-12-12
  • 項目總結(jié)之HttpURLConnection的disconnect的問題

    項目總結(jié)之HttpURLConnection的disconnect的問題

    這篇文章主要介紹了項目總結(jié)之HttpURLConnection的disconnect的問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2023-06-06
  • SpringBoot創(chuàng)建并簡單使用的實現(xiàn)

    SpringBoot創(chuàng)建并簡單使用的實現(xiàn)

    這篇文章主要介紹了SpringBoot創(chuàng)建并簡單使用的實現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-10-10
  • JetCache?緩存框架的使用及源碼解析(推薦)

    JetCache?緩存框架的使用及源碼解析(推薦)

    JetCache是一個基于Java的緩存系統(tǒng)封裝,提供統(tǒng)一的API和注解來簡化緩存的使用。本文重點給大家介紹JetCache?緩存框架的使用及源碼分析,感興趣的朋友一起看看吧
    2022-01-01
  • 詳解Java的設(shè)計模式編程中的原型模式

    詳解Java的設(shè)計模式編程中的原型模式

    這篇文章主要介紹了Java的設(shè)計模式編程中的原型模式,處理對象復(fù)制時要特別注意淺拷貝和深拷貝的問題,需要的朋友可以參考下
    2016-02-02

最新評論

东乡| 龙陵县| 娱乐| 历史| 洪江市| 光泽县| 健康| 四平市| 会同县| 织金县| 喀什市| 高碑店市| 茂名市| 抚顺县| 甘南县| 建瓯市| 黄浦区| 体育| 双柏县| 牟定县| 加查县| 秭归县| 连平县| 安阳市| 正定县| 都江堰市| 宜黄县| 城步| 厦门市| 和田市| 秭归县| 彭水| 太原市| 芮城县| 琼结县| 育儿| 章丘市| 鲁山县| 绥宁县| 平顶山市| 介休市|