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

SpringBoot配置的加載流程詳細分析

 更新時間:2023年01月06日 11:48:21   作者:起風哥  
了解內(nèi)部原理是為了幫助我們做擴展,同時也是驗證了一個人的學習能力,如果你想讓自己的職業(yè)道路更上一層樓,這些底層的東西你是必須要會的,這篇文章主要介紹了SpringBoot配置的加載流程

在上一篇Springboot啟動流程解析中我們沒有張開對配置的解析,因為篇幅過大,需要單獨在起一篇文章來講。

且看一下兩行代碼:

ApplicationArguments applicationArguments = new DefaultApplicationArguments(
					args);
			ConfigurableEnvironment environment = prepareEnvironment(listeners,
					applicationArguments);

第一行代碼是對控制臺入?yún)⒆隽私馕鲰樦a跟進去我們發(fā)現(xiàn)

先調(diào)用SimpleCommandLineArgsParser來解析對應的控制臺入?yún)ⅲ馕鐾曛笤趤G給父類進行處理

public SimpleCommandLinePropertySource(String... args) {
		super(new SimpleCommandLineArgsParser().parse(args));
	}

所以接下來我們看這個parse方法:

public CommandLineArgs parse(String... args) {
		//構(gòu)建個緩存,將解析的參數(shù)分別放入兩個容器中,分為兩種類型的熟悉選項參數(shù)和非選項參數(shù),選項參數(shù)使用 --開頭
		CommandLineArgs commandLineArgs = new CommandLineArgs();
		for (String arg : args) {
			if (arg.startsWith("--")) {
				String optionText = arg.substring(2, arg.length());
				String optionName;
				String optionValue = null;
				if (optionText.contains("=")) {
					optionName = optionText.substring(0, optionText.indexOf('='));
					optionValue = optionText.substring(optionText.indexOf('=')+1, optionText.length());
				}
				else {
					optionName = optionText;
				}
				if (optionName.isEmpty() || (optionValue != null && optionValue.isEmpty())) {
					throw new IllegalArgumentException("Invalid argument syntax: " + arg);
				}
				commandLineArgs.addOptionArg(optionName, optionValue);
			}
			else {
				commandLineArgs.addNonOptionArg(arg);
			}
		}
		return commandLineArgs;
	}

以上代碼就做了件很簡單的事情,將遍歷所有的入?yún)ⅲ缓笈袛鄈ey是否包含"–“如果包含丟到OptionArg 中 ,不包含就丟到NonOptionArg中,并且將commandLineArgs返回。就做了個分類動作含”–"的寫法標準注解也給出來了 ,必須按下面這種寫法

--foo
--foo=bar
--foo="bar then baz"
--foo=bar,baz,biz

好此時我們已經(jīng)獲得了一個分好類的參數(shù)對象,丟給父類在加工,發(fā)現(xiàn)父類又丟給了父類,但是我們發(fā)現(xiàn) 父類已經(jīng)是一個PropertySource的子類,所以最后這里被封裝成了一個PropertySource對象,實際上就是把返回的commandLineArgs對象緩存起來,最終通過提供的抽象方法,可以獲取到對應的屬性。

public CommandLinePropertySource(T source) {
		super(COMMAND_LINE_PROPERTY_SOURCE_NAME, source);
	}

所以我們回過頭看SimpleCommandLinePropertySource 和DefaultApplicationArguments即可。從簡單的代碼上我們可以很容易看出來,無非最后就是從兩個集合當中取key value,所以直接把它當做一個map就好了,代碼也不貼了。

接著看第二行代碼,這個才是我們的主菜

發(fā)現(xiàn)沒有,寫代碼的層次結(jié)構(gòu),思維思想,都是一個模式

一個復雜的過程就是 先prepare -->init -->createA–>creatB–>complete.優(yōu)秀的人寫代碼就跟寫文章一樣。一看就很好懂得那種。

private ConfigurableEnvironment prepareEnvironment(
			SpringApplicationRunListeners listeners,
			ApplicationArguments applicationArguments) {
		//進來第一步先聲明一個可配置的環(huán)境變量容器
		ConfigurableEnvironment environment = getOrCreateEnvironment();
		//然后配置它
		configureEnvironment(environment, applicationArguments.getSourceArgs());
		//然后發(fā)布給事件出去告訴所有l(wèi)istener 環(huán)境配置完成
		listeners.environmentPrepared(environment);
		//把環(huán)境綁定給springboot
		bindToSpringApplication(environment);
		if (!this.isCustomEnvironment) {
			environment = new EnvironmentConverter(getClassLoader())
					.convertEnvironmentIfNecessary(environment, deduceEnvironmentClass());
		}
		ConfigurationPropertySources.attach(environment);
		return environment;
	}

針對以上代碼我們接著一行行展開創(chuàng)建,這里就是根據(jù)不同容器創(chuàng)建不同的對象。

	private ConfigurableEnvironment getOrCreateEnvironment() {
		if (this.environment != null) {
			return this.environment;
		}
		switch (this.webApplicationType) {
		case SERVLET:
			return new StandardServletEnvironment();
		case REACTIVE:
			return new StandardReactiveWebEnvironment();
		default:
			return new StandardEnvironment();
		}
	}

根據(jù)Environment的繼承關(guān)系我們不難看出在對象創(chuàng)建時就調(diào)用了customizePropertySources(this.propertySources);方法

此時也就是往容器中初始化了兩個對象 一個時 system一個時env,這兩個變量的參數(shù)就是系統(tǒng)和jvm級別的變量對象

@Override
	protected void customizePropertySources(MutablePropertySources propertySources) {
		propertySources.addLast(new MapPropertySource(SYSTEM_PROPERTIES_PROPERTY_SOURCE_NAME, getSystemProperties()));
		propertySources.addLast(new SystemEnvironmentPropertySource(SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME, getSystemEnvironment()));
	}

而傳入的MutablePropertySources 直接由父類抽象類直接new出來的,通過查看這個類我們可很清楚的知道它也是一個數(shù)據(jù)存儲結(jié)構(gòu),緩存了一個Propertysource的列表。剩下的就是對它的增刪改等處理操作。

所以我們來看這一行

configureEnvironment(environment,applicationArguments.getSourceArgs());

在這段代碼中放了個類型轉(zhuǎn)換服務,這個類型轉(zhuǎn)換服務,也是一整套的體系,內(nèi)置了各種各樣的類型轉(zhuǎn)換,比如你在配置文件寫了個 時間 100ms 它到底是怎么被識別成100毫秒的,都是通過這個類型轉(zhuǎn)換服務轉(zhuǎn)換的。有興趣可以自行拓展開

protected void configureEnvironment(ConfigurableEnvironment environment,
			String[] args) {
		if (this.addConversionService) {
			ConversionService conversionService = ApplicationConversionService
					.getSharedInstance();
			environment.setConversionService(
					(ConfigurableConversionService) conversionService);
		}
		configurePropertySources(environment, args);
		configureProfiles(environment, args);
	}

接著往里走

configurePropertySources(environment, args);

這里代碼還是將拿到上面配置的緩存往里面在塞propertysource對象

protected void configurePropertySources(ConfigurableEnvironment environment,
			String[] args) {
		MutablePropertySources sources = environment.getPropertySources();
		if (this.defaultProperties != null && !this.defaultProperties.isEmpty()) {
			sources.addLast(
					new MapPropertySource("defaultProperties", this.defaultProperties));
		}
		if (this.addCommandLineProperties && args.length > 0) {
			String name = CommandLinePropertySource.COMMAND_LINE_PROPERTY_SOURCE_NAME;
			if (sources.contains(name)) {
				PropertySource<?> source = sources.get(name);
				CompositePropertySource composite = new CompositePropertySource(name);
				composite.addPropertySource(new SimpleCommandLinePropertySource(
						"springApplicationCommandLineArgs", args));
				composite.addPropertySource(source);
				sources.replace(name, composite);
			}
			else {
				sources.addFirst(new SimpleCommandLinePropertySource(args));
			}
		}
	}

從代碼可以看出,獲取了一個defaultProperties 的map把它也加入到list中。而這個map也是在main函數(shù)進行設置的,而這個屬性是出了系統(tǒng)屬性的之外最早加載的propertysource對象

public static void main(String[] args) {
        SpringApplicationBuilder builder = new SpringApplicationBuilder();
        builder.properties(map);
        builder.run(Application.class,args);
    }

然后我們回過頭來看configureProfiles方法,此方法等以上配置完成之后,先從配置中抽取出profiles 并將其作為單獨的屬性設置回去。抽取規(guī)則看如下代碼

	protected Set<String> doGetActiveProfiles() {
		synchronized (this.activeProfiles) {
			if (this.activeProfiles.isEmpty()) {
				String profiles = getProperty(ACTIVE_PROFILES_PROPERTY_NAME);
				if (StringUtils.hasText(profiles)) {
					setActiveProfiles(StringUtils.commaDelimitedListToStringArray(
							StringUtils.trimAllWhitespace(profiles)));
				}
			}
			return this.activeProfiles;
		}
	}

最終所有的getProperty都走到如下代碼,而這段代碼也很簡單就是遍歷所有的propertysource ,如果取到則終止,也就給我們營造了一個假象,就是同一個配置被覆蓋的假象。不是真真的被覆蓋,而是放在不同的propertysource中,并且propertysource有順序而已。

protected <T> T getProperty(String key, Class<T> targetValueType, boolean resolveNestedPlaceholders) {
		if (this.propertySources != null) {
			for (PropertySource<?> propertySource : this.propertySources) {
				if (logger.isTraceEnabled()) {
					logger.trace("Searching for key '" + key + "' in PropertySource '" +
							propertySource.getName() + "'");
				}
				Object value = propertySource.getProperty(key);
				if (value != null) {
					if (resolveNestedPlaceholders && value instanceof String) {
						value = resolveNestedPlaceholders((String) value);
					}
					logKeyFound(key, propertySource, value);
					return convertValueIfNecessary(value, targetValueType);
				}
			}
		}
		if (logger.isTraceEnabled()) {
			logger.trace("Could not find key '" + key + "' in any property source");
		}
		return null;
	}

通過以上的代碼分析我們可以知道一件事情放在越底層的propertysource 會被上層的覆蓋,通過巧妙的利用這一點,我們就以通過不同入?yún)⒎绞竭M行不同環(huán)境的變量覆蓋,比如在項目中配置了配置中心為 測試環(huán)境,發(fā)布到生產(chǎn)是不是可以使用環(huán)境變量放在它的上層,就達到覆蓋效果。而不用在打包的時候去改配置。

關(guān)于propertysource總體數(shù)據(jù)結(jié)構(gòu)體系設計下回分解。

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

相關(guān)文章

  • Spring boot Mybatis 整合(完整版)

    Spring boot Mybatis 整合(完整版)

    本文是一篇比較完整的版本通過圖文并茂的形式給大家介紹了Spring boot Mybatis 整合過程,感興趣的朋友跟隨腳本之家小編一起看看吧
    2018-09-09
  • Mybatis plus通用字段自動填充的示例

    Mybatis plus通用字段自動填充的示例

    這篇文章主要介紹了Mybatis plus通用字段自動填充的示例,幫助大家更好的理解和使用Mybatis,感興趣的朋友可以了解下
    2021-01-01
  • 詳解Java生成PDF文檔方法

    詳解Java生成PDF文檔方法

    這篇文章主要介紹了Java生成PDF文檔方法,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2019-04-04
  • JDK1.8新特性之方法引用 ::和Optional詳解

    JDK1.8新特性之方法引用 ::和Optional詳解

    這篇文章主要介紹了JDK1.8新特性之方法引用 ::和Optional,本文通過實例代碼給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2021-09-09
  • Java異步調(diào)用轉(zhuǎn)同步的方法

    Java異步調(diào)用轉(zhuǎn)同步的方法

    這篇文章主要介紹了Java異步調(diào)用轉(zhuǎn)同步的方法,幫助大家更好的理解和使用Java,感興趣的朋友可以了解下
    2020-12-12
  • 淺析Java如何優(yōu)雅的避免那無處不在的空指針異常

    淺析Java如何優(yōu)雅的避免那無處不在的空指針異常

    在Java編程語言中,NullPointerException(簡稱NPE)是一種常見的運行時異常,本文主要來和大家講講如何優(yōu)雅的避免這些空指針異常,需要的可以參考下
    2024-03-03
  • Java深入淺出掌握SpringBoot之MVC自動配置原理篇

    Java深入淺出掌握SpringBoot之MVC自動配置原理篇

    在進行項目編寫前,我們還需要知道一個東西,就是SpringBoot對我們的SpringMVC還做了哪些配置,包括如何擴展,如何定制,只有把這些都搞清楚了,我們在之后使用才會更加得心應手
    2021-10-10
  • Java 中的偽共享詳解及解決方案

    Java 中的偽共享詳解及解決方案

    這篇文章主要介紹了Java 中的偽共享詳解及解決方案,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2020-02-02
  • 解決SpringMvc中普通類注入Service為null的問題

    解決SpringMvc中普通類注入Service為null的問題

    這篇文章主要介紹了解決SpringMvc中普通類注入Service為null的問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-07-07
  • 如何解決mybatis查詢結(jié)果接收不同的問題

    如何解決mybatis查詢結(jié)果接收不同的問題

    這篇文章主要介紹了如何解決mybatis查詢結(jié)果接收不同的問題,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下
    2020-09-09

最新評論

安多县| 新乡市| 新乡县| 射阳县| 汉源县| 思茅市| 涿鹿县| 无为县| 中牟县| 余姚市| 莒南县| 延寿县| 鹤壁市| 高阳县| 观塘区| 临泽县| 阜南县| 汉源县| 稷山县| 临漳县| 东平县| 左贡县| 栾城县| 南岸区| 乐陵市| 文山县| 昔阳县| 武陟县| 娄烦县| 洮南市| 老河口市| 鱼台县| 北辰区| 九江县| 巴青县| 葵青区| 格尔木市| 钟山县| 岳普湖县| 土默特右旗| 崇信县|