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

SpringBoot bean查詢加載順序流程詳解

 更新時間:2023年03月12日 11:34:45   作者:amcomputer  
當你在項目啟動時需要提前做一個業(yè)務(wù)的初始化工作時,或者你正在開發(fā)某個中間件需要完成自動裝配時。你會聲明自己的Configuration類,但是可能你面對的是好幾個有互相依賴的Bean

背景

SpringBoot bean 加載順序如何查看,想看加載了哪些bean, 這些bean的加載順序是什么?

實際加載順序不受控制,但會有一些大的原則:

1、按照字母順序加載(同一文件夾下按照字母數(shù)序;不同文件夾下,先按照文件夾命名的字母順序加載)
2、不同的bean聲明方式不同的加載時機,順序總結(jié):@ComponentScan > @Import > @Bean
   這里的ComponentScan指@ComponentScan及其子注解,Bean指的是@configuration + @bean
   同時需要注意的是:
   (1)Component及其子注解申明的bean是按照字母順序加載的
   (2)@configuration + @bean是按照定義的順序依次加載的
   (3)@import的順序,就是bean的加載順序
   (4)在xml中,通過<bean id="">方式聲明的bean也是按照代碼的編寫順序依次加載的
   (5)同一類中加載順序:Constructor >> @Autowired >> @PostConstruct >> @Bean
   (6)同一類中加載順序:靜態(tài)變量 / 靜態(tài)代碼塊 >> 構(gòu)造代碼塊 >> 構(gòu)造方法(需要特別注意的是靜態(tài)代碼塊的執(zhí)行并不是優(yōu)先所有的bean加載,只是在同一個類中,靜態(tài)代碼塊優(yōu)先加載)

探索-源碼

入口:

public class TestApplication {
	public static void main(String[] args) {
		try {
			SpringApplication.run(TestApplication.class, args);
			LOGGER.info("SpringBoot Application Start!!!");
		} catch (Throwable e) {
			throw e;
		}
	}
}

其中 里面的run方法為:

	public ConfigurableApplicationContext run(String... args) {
		long startTime = System.nanoTime();
		DefaultBootstrapContext bootstrapContext = createBootstrapContext();
		ConfigurableApplicationContext context = null;
		configureHeadlessProperty();
		SpringApplicationRunListeners listeners = getRunListeners(args);
		listeners.starting(bootstrapContext, this.mainApplicationClass);
		try {
			ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
			ConfigurableEnvironment environment = prepareEnvironment(listeners, bootstrapContext, applicationArguments);
			configureIgnoreBeanInfo(environment);
			Banner printedBanner = printBanner(environment);
			context = createApplicationContext();
			context.setApplicationStartup(this.applicationStartup);
			prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);
			**refreshContext**(context);
			afterRefresh(context, applicationArguments);
			Duration timeTakenToStartup = Duration.ofNanos(System.nanoTime() - startTime);
			if (this.logStartupInfo) {
				new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), timeTakenToStartup);
			}
			listeners.started(context, timeTakenToStartup);
			callRunners(context, applicationArguments);
		}
		catch (Throwable ex) {
			handleRunFailure(context, ex, listeners);
			throw new IllegalStateException(ex);
		}
		try {
			Duration timeTakenToReady = Duration.ofNanos(System.nanoTime() - startTime);
			listeners.ready(context, timeTakenToReady);
		}
		catch (Throwable ex) {
			handleRunFailure(context, ex, null);
			throw new IllegalStateException(ex);
		}
		return context;
	}

refreshContext(context);

	private void refreshContext(ConfigurableApplicationContext context) {
		if (this.registerShutdownHook) {
			shutdownHook.registerApplicationContext(context);
		}
		**refresh**(context);
	}

AbstractApplicationContext#refresh

然后看倒數(shù)第二行:finishBeanFactoryInitialization(beanFactory);

org.springframework.context.support.AbstractApplicationContext#refresh

	@Override
	public void refresh() throws BeansException, IllegalStateException {
		synchronized (this.startupShutdownMonitor) {
			StartupStep contextRefresh = this.applicationStartup.start("spring.context.refresh");
			// Prepare this context for refreshing.
			prepareRefresh();
			// Tell the subclass to refresh the internal bean factory.
			ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
			// Prepare the bean factory for use in this context.
			prepareBeanFactory(beanFactory);
				// Allows post-processing of the bean factory in context subclasses.
				postProcessBeanFactory(beanFactory);
				StartupStep beanPostProcess = this.applicationStartup.start("spring.context.beans.post-process");
				// Invoke factory processors registered as beans in the context.
				invokeBeanFactoryPostProcessors(beanFactory);
				// Register bean processors that intercept bean creation.
				registerBeanPostProcessors(beanFactory);
				beanPostProcess.end();
				// Initialize message source for this context.
				initMessageSource();
				// Initialize event multicaster for this context.
				initApplicationEventMulticaster();
				// Initialize other special beans in specific context subclasses.
				onRefresh();
				// Check for listener beans and register them.
				registerListeners();
				// Instantiate all remaining (non-lazy-init) singletons.
				**finishBeanFactoryInitialization(beanFactory);**
				// Last step: publish corresponding event.
				finishRefresh();
			}

finishBeanFactoryInitialization(beanFactory)

然后看最后一行:beanFactory.preInstantiateSingletons();

	protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
		// Initialize conversion service for this context.
		if (beanFactory.containsBean(CONVERSION_SERVICE_BEAN_NAME) &&
				beanFactory.isTypeMatch(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class)) {
			beanFactory.setConversionService(
					beanFactory.getBean(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class));
		}
		// Register a default embedded value resolver if no BeanFactoryPostProcessor
		// (such as a PropertySourcesPlaceholderConfigurer bean) registered any before:
		// at this point, primarily for resolution in annotation attribute values.
		if (!beanFactory.hasEmbeddedValueResolver()) {
			beanFactory.addEmbeddedValueResolver(strVal -> getEnvironment().resolvePlaceholders(strVal));
		}
		// Initialize LoadTimeWeaverAware beans early to allow for registering their transformers early.
		String[] weaverAwareNames = beanFactory.getBeanNamesForType(LoadTimeWeaverAware.class, false, false);
		for (String weaverAwareName : weaverAwareNames) {
			getBean(weaverAwareName);
		}
		// Stop using the temporary ClassLoader for type matching.
		beanFactory.setTempClassLoader(null);
		// Allow for caching all bean definition metadata, not expecting further changes.
		beanFactory.freezeConfiguration();
		// Instantiate all remaining (non-lazy-init) singletons.
		**beanFactory.preInstantiateSingletons();**
	}

beanFactory.preInstantiateSingletons()

在這里會對 beanDefinitionNames 進行遍歷,然后進行 bean的實例化 和 組裝

因此這里的 beanDefinitionNames 這個列表決定了bean 的 注冊順序。

org.springframework.beans.factory.support.DefaultListableBeanFactory#preInstantiateSingletons

@Override
	public void preInstantiateSingletons() throws BeansException {
		if (logger.isTraceEnabled()) {
			logger.trace("Pre-instantiating singletons in " + this);
		}
		// Iterate over a copy to allow for init methods which in turn register new bean definitions.
		// While this may not be part of the regular factory bootstrap, it does otherwise work fine.
		**List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);**
		// Trigger initialization of all non-lazy singleton beans...
		for (String beanName : beanNames) {
			RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
			if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
				if (isFactoryBean(beanName)) {
					Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);
					if (bean instanceof FactoryBean) {
						FactoryBean<?> factory = (FactoryBean<?>) bean;
						boolean isEagerInit;
						if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {
							isEagerInit = AccessController.doPrivileged(
									(PrivilegedAction<Boolean>) ((SmartFactoryBean<?>) factory)::isEagerInit,
									getAccessControlContext());
						}
						else {
							isEagerInit = (factory instanceof SmartFactoryBean &&
									((SmartFactoryBean<?>) factory).isEagerInit());
						}
						if (isEagerInit) {
							getBean(beanName);
						}
					}
				}
				else {
					getBean(beanName);
				}
			}
		}
		// Trigger post-initialization callback for all applicable beans...
		for (String beanName : beanNames) {
			Object singletonInstance = getSingleton(beanName);
			if (singletonInstance instanceof SmartInitializingSingleton) {
				StartupStep smartInitialize = this.getApplicationStartup().start("spring.beans.smart-initialize")
						.tag("beanName", beanName);
				SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton) singletonInstance;
				if (System.getSecurityManager() != null) {
					AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
						smartSingleton.afterSingletonsInstantiated();
						return null;
					}, getAccessControlContext());
				}
				else {
					smartSingleton.afterSingletonsInstantiated();
				}
				smartInitialize.end();
			}
		}
	}

如果不能看,像圖中一樣,不能找到j(luò)ava.util.list這個類,可以使用下面這個方式,親測有效:

beanDefinitionNames.toArray()

后面的bean就不展示順序了。感興趣的讀者可以看自己springBoot項目的。

進一步思考

beanDefinitionNames 列表如何來的呢?

答案是 ConfigurationClassPostProcessor 通過掃描 代碼+注解生成的,講bean 掃描解析成 beanDefinition, 同時把 bean定義,beanDefinition,注冊到 BeanDefinitionRegistry, 故有了beanDefinitionNames list。

到此這篇關(guān)于SpringBoot bean查詢加載順序流程詳解的文章就介紹到這了,更多相關(guān)SpringBoot bean加載順序內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • springboot操作靜態(tài)資源文件的方法

    springboot操作靜態(tài)資源文件的方法

    這篇文章主要介紹了springboot操作靜態(tài)資源文件的方法,本文給大家提到了兩種方法,小編在這里比較推薦第一種方法,具體內(nèi)容詳情大家跟隨腳本之家小編一起看看吧
    2018-07-07
  • springboot返回html和jsp的方法示例

    springboot返回html和jsp的方法示例

    這篇文章主要介紹了springboot返回html和jsp的方法示例,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2020-12-12
  • Java數(shù)據(jù)結(jié)構(gòu)常見幾大排序梳理

    Java數(shù)據(jù)結(jié)構(gòu)常見幾大排序梳理

    Java常見的排序算法有:直接插入排序、希爾排序、選擇排序、冒泡排序、歸并排序、快速排序、堆排序等。本文詳解介紹它們的實現(xiàn)以及圖解,需要的可以參考一下
    2022-03-03
  • Spring注入Bean的一些方式總結(jié)

    Spring注入Bean的一些方式總結(jié)

    這篇文章主要給大家總結(jié)介紹了關(guān)于Spring注入Bean的一些方式,文中通過示例代碼介紹的非常詳細,對大家學習或者使用Spring具有一定的參考學習價值,需要的朋友們下面來一起學習學習吧
    2019-04-04
  • Java開發(fā)學習 Eclipse項目有紅感嘆號解決之道

    Java開發(fā)學習 Eclipse項目有紅感嘆號解決之道

    這篇文章主要為大家詳細介紹了完美解決Eclipse項目有紅感嘆號問題的方法,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2017-04-04
  • 詳解關(guān)于Windows10 Java環(huán)境變量配置問題的解決辦法

    詳解關(guān)于Windows10 Java環(huán)境變量配置問題的解決辦法

    這篇文章主要介紹了關(guān)于Windows10 Java環(huán)境變量配置問題的解決辦法,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2019-03-03
  • spring?boot?validation參數(shù)校驗與分組嵌套各種類型及使用小結(jié)

    spring?boot?validation參數(shù)校驗與分組嵌套各種類型及使用小結(jié)

    參數(shù)校驗基本上是controller必做的事情,畢竟前端傳過來的一切都不可信,validation可以簡化這一操作,這篇文章主要介紹了spring?boot?validation參數(shù)校驗分組嵌套各種類型及使用小結(jié),需要的朋友可以參考下
    2023-09-09
  • 基于SpringBoot實現(xiàn)離線應(yīng)用的4種實現(xiàn)方式

    基于SpringBoot實現(xiàn)離線應(yīng)用的4種實現(xiàn)方式

    在當今高度依賴網(wǎng)絡(luò)的環(huán)境中,離線應(yīng)用的價值日益凸顯,而且具備離線工作能力已成為許多應(yīng)用的必備特性,本文將介紹基于SpringBoot實現(xiàn)離線應(yīng)用的4種不同方式
    2025-06-06
  • 淺談Java后臺對JSON格式的處理操作

    淺談Java后臺對JSON格式的處理操作

    下面小編就為大家?guī)硪黄獪\談Java后臺對JSON格式的處理操作。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2016-06-06
  • EVCache緩存在Spring Boot中的實戰(zhàn)示例

    EVCache緩存在Spring Boot中的實戰(zhàn)示例

    這篇文章主要介紹了EVCache緩存在Spring Boot中的實戰(zhàn)示例,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2018-12-12

最新評論

南皮县| 安达市| 阿拉善左旗| 石狮市| 嘉禾县| 高尔夫| 兰考县| 南开区| 石首市| 延川县| 巴彦淖尔市| 六枝特区| 抚顺市| 阳东县| 凤山市| 韶山市| 庆阳市| 新干县| 健康| 修武县| 松潘县| 达尔| 涿鹿县| 洪江市| 资中县| 普格县| 年辖:市辖区| 新蔡县| 甘泉县| 丹寨县| 会东县| 新龙县| 辰溪县| 新干县| 洮南市| 文成县| 长丰县| 铜陵市| 永清县| 丰宁| 兴文县|