亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

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

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

一、從示例開(kāi)始

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

來(lái)看下面示例。

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");
    }
}

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

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

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

二、創(chuàng)建AnnotationConfigApplicationContext

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

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

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

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

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

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

三、注冊(cè)Configuration類(lèi)

3.1 創(chuàng)建BeanDefinition

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

來(lái)看AnnotatedBeanDefinitionReader#doRegisterBean的核心邏輯:

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

3.2 注冊(cè)BeanDefinition

BeanDefinitionHolder類(lèi)只是對(duì)BeanDefinition的包裝,僅有三個(gè)屬性:beanDefinition、beanName和aliases。

在BeanDefinitionReaderUtils#registerBeanDefinition中

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

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

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

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

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

四、掃描包路徑

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

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

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

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

4.1 BeanFactoryPostProcessor接口

先看類(lèi)注釋?zhuān)?/p>

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實(shí)例交互。

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

僅有一個(gè)方法:

void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException;

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

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

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

4.2 ConfigurationClassPostProcessor類(lèi)

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

在ConfigurationClassPostProcessor#processConfigBeanDefinitions中,

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

  • 類(lèi)上有@Configuration注解;
  • 類(lèi)上有以下任意一個(gè)注解;

  • 類(lèi)中有@Bean注解的方法;

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

接下來(lái)會(huì)遍歷處理每一個(gè)候選類(lèi)

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

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

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

五、邏輯閉環(huán)

要用ConfigurationClassPostProcessor來(lái)處理配置類(lèi),Spring容器中就得先有該類(lèi)的實(shí)例。那么,這個(gè)類(lèi)是何時(shí)注冊(cè)到容器中的?

答案就在new AnnotatedBeanDefinitionReader(this)中:

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

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

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

流程圖

總結(jié)

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

相關(guān)文章

  • SPRING IOC注入方式過(guò)程解析

    SPRING IOC注入方式過(guò)程解析

    這篇文章主要介紹了SPRING IOC注入方式過(guò)程解析,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-01-01
  • Java中將多個(gè)PDF文件合并為一個(gè)PDF的方法步驟

    Java中將多個(gè)PDF文件合并為一個(gè)PDF的方法步驟

    這篇文章主要給大家介紹了關(guān)于Java中將多個(gè)PDF文件合并為一個(gè)PDF的方法步驟, Java PDF合并是指將多個(gè)PDF文件合并成一個(gè)PDF文件的過(guò)程,需要的朋友可以參考下
    2023-09-09
  • 關(guān)于Spring?Validation數(shù)據(jù)校檢的使用流程分析

    關(guān)于Spring?Validation數(shù)據(jù)校檢的使用流程分析

    在實(shí)際項(xiàng)目中,對(duì)客戶(hù)端傳遞到服務(wù)端的參數(shù)進(jìn)行校驗(yàn)至關(guān)重要,SpringValidation提供了一種便捷的方式來(lái)實(shí)現(xiàn)這一需求,通過(guò)在POJO類(lèi)的屬性上添加檢查注解,本文給大家介紹Spring?Validation數(shù)據(jù)校檢的使用流程,感興趣的朋友一起看看吧
    2024-11-11
  • Java中實(shí)現(xiàn)線程間通信的實(shí)例教程

    Java中實(shí)現(xiàn)線程間通信的實(shí)例教程

    線程通信的目標(biāo)是使線程間能夠互相發(fā)送信號(hào),另一方面線程通信使線程能夠等待其他線程的信號(hào),這篇文章主要給大家介紹了關(guān)于Java中實(shí)現(xiàn)線程間通信的相關(guān)資料,本文通過(guò)示例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2021-09-09
  • 使用MyBatis返回其它類(lèi)對(duì)象的字段處理

    使用MyBatis返回其它類(lèi)對(duì)象的字段處理

    這篇文章主要介紹了使用MyBatis返回其它類(lèi)對(duì)象的字段處理方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-08-08
  • Java使用POI從Excel讀取數(shù)據(jù)并存入數(shù)據(jù)庫(kù)(解決讀取到空行問(wèn)題)

    Java使用POI從Excel讀取數(shù)據(jù)并存入數(shù)據(jù)庫(kù)(解決讀取到空行問(wèn)題)

    有時(shí)候需要在java中讀取excel文件的內(nèi)容,專(zhuān)業(yè)的方式是使用java POI對(duì)excel進(jìn)行讀取,這篇文章主要給大家介紹了關(guān)于Java使用POI從Excel讀取數(shù)據(jù)并存入數(shù)據(jù)庫(kù),文中介紹的辦法可以解決讀取到空行問(wèn)題,需要的朋友可以參考下
    2023-12-12
  • 一天時(shí)間用Java寫(xiě)了個(gè)飛機(jī)大戰(zhàn)游戲,朋友直呼高手

    一天時(shí)間用Java寫(xiě)了個(gè)飛機(jī)大戰(zhàn)游戲,朋友直呼高手

    前兩天我發(fā)現(xiàn)論壇有兩篇飛機(jī)大戰(zhàn)的文章異常火爆,但都是python寫(xiě)的,竟然不是我大Java,說(shuō)實(shí)話(huà)作為老java選手,我心里是有那么一些失落的,今天特地整理了這篇文章,需要的朋友可以參考下
    2021-05-05
  • SpringBoot整合minio服務(wù)的示例代碼

    SpringBoot整合minio服務(wù)的示例代碼

    本文主要介紹了SpringBoot整合minio服務(wù)的示例代碼,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2023-06-06
  • IDEA檢查項(xiàng)目的jdk版本需要看的地方

    IDEA檢查項(xiàng)目的jdk版本需要看的地方

    這篇文章主要介紹了IDEA檢查項(xiàng)目的jdk版本需要看的地方,文中通過(guò)圖文介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2024-06-06
  • 理解Java當(dāng)中的回調(diào)機(jī)制(翻譯)

    理解Java當(dāng)中的回調(diào)機(jī)制(翻譯)

    今天我要和大家分享一些東西,舉例來(lái)說(shuō)這個(gè)在JavaScript中用的很多。我要講講回調(diào)(callbacks)。你知道什么時(shí)候用,怎么用這個(gè)嗎?你真的理解了它在java環(huán)境中的用法了嗎?當(dāng)我也問(wèn)我自己這些問(wèn)題,這也是我開(kāi)始研究這些的原因
    2014-10-10

最新評(píng)論