欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

SpringBoot配置的加載流程詳細(xì)分析

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

在上一篇Springboot啟動(dòng)流程解析中我們沒有張開對(duì)配置的解析,因?yàn)槠^大,需要單獨(dú)在起一篇文章來講。

且看一下兩行代碼:

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

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

先調(diào)用SimpleCommandLineArgsParser來解析對(duì)應(yīng)的控制臺(tái)入?yún)?,解析完之后在丟給父類進(jìn)行處理

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

所以接下來我們看這個(gè)parse方法:

public CommandLineArgs parse(String... args) {
		//構(gòu)建個(gè)緩存,將解析的參數(shù)分別放入兩個(gè)容器中,分為兩種類型的熟悉選項(xiàng)參數(shù)和非選項(xiàng)參數(shù),選項(xiàng)參數(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;
	}

以上代碼就做了件很簡(jiǎn)單的事情,將遍歷所有的入?yún)?,然后判斷key是否包含"–“如果包含丟到OptionArg 中 ,不包含就丟到NonOptionArg中,并且將commandLineArgs返回。就做了個(gè)分類動(dòng)作含”–"的寫法標(biāo)準(zhǔn)注解也給出來了 ,必須按下面這種寫法

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

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

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

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

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

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

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

private ConfigurableEnvironment prepareEnvironment(
			SpringApplicationRunListeners listeners,
			ApplicationArguments applicationArguments) {
		//進(jìn)來第一步先聲明一個(gè)可配置的環(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;
	}

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

	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)系我們不難看出在對(duì)象創(chuàng)建時(shí)就調(diào)用了customizePropertySources(this.propertySources);方法

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

@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出來的,通過查看這個(gè)類我們可很清楚的知道它也是一個(gè)數(shù)據(jù)存儲(chǔ)結(jié)構(gòu),緩存了一個(gè)Propertysource的列表。剩下的就是對(duì)它的增刪改等處理操作。

所以我們來看這一行

configureEnvironment(environment,applicationArguments.getSourceArgs());

在這段代碼中放了個(gè)類型轉(zhuǎn)換服務(wù),這個(gè)類型轉(zhuǎn)換服務(wù),也是一整套的體系,內(nèi)置了各種各樣的類型轉(zhuǎn)換,比如你在配置文件寫了個(gè) 時(shí)間 100ms 它到底是怎么被識(shí)別成100毫秒的,都是通過這個(gè)類型轉(zhuǎn)換服務(wù)轉(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對(duì)象

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

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

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

然后我們回過頭來看configureProfiles方法,此方法等以上配置完成之后,先從配置中抽取出profiles 并將其作為單獨(dú)的屬性設(shè)置回去。抽取規(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都走到如下代碼,而這段代碼也很簡(jiǎn)單就是遍歷所有的propertysource ,如果取到則終止,也就給我們營(yíng)造了一個(gè)假象,就是同一個(gè)配置被覆蓋的假象。不是真真的被覆蓋,而是放在不同的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 會(huì)被上層的覆蓋,通過巧妙的利用這一點(diǎn),我們就以通過不同入?yún)⒎绞竭M(jìn)行不同環(huán)境的變量覆蓋,比如在項(xiàng)目中配置了配置中心為 測(cè)試環(huán)境,發(fā)布到生產(chǎn)是不是可以使用環(huán)境變量放在它的上層,就達(dá)到覆蓋效果。而不用在打包的時(shí)候去改配置。

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

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

相關(guān)文章

  • 如何使用@ConditionalOnExpression決定是否生效注釋

    如何使用@ConditionalOnExpression決定是否生效注釋

    這篇文章主要介紹了如何使用@ConditionalOnExpression決定是否生效注釋的操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-06-06
  • Java使用poi生成word文檔的簡(jiǎn)單實(shí)例

    Java使用poi生成word文檔的簡(jiǎn)單實(shí)例

    Java POI是一個(gè)用于處理Microsoft Office文件(如Word、Excel和PowerPoint)的API,它是一個(gè)開源庫,允許Java開發(fā)者讀取、創(chuàng)建和修改這些文檔,本文給大集介紹了Java使用poi生成word文檔的簡(jiǎn)單實(shí)例,感興趣的朋友可以參考下
    2024-06-06
  • java新手入門——String類詳解

    java新手入門——String類詳解

    在java、C#中,String類是不可變的,對(duì)String類的任何改變,都是返回一個(gè)新的String類對(duì)象。string>是C++標(biāo)準(zhǔn)程序庫中的一個(gè)頭文件
    2021-06-06
  • 關(guān)于Mybatis-Plus?Update更新策略問題

    關(guān)于Mybatis-Plus?Update更新策略問題

    這篇文章主要介紹了關(guān)于Mybatis-Plus?Update更新策略問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-11-11
  • Java之Springcloud Gateway內(nèi)置路由案例講解

    Java之Springcloud Gateway內(nèi)置路由案例講解

    這篇文章主要介紹了Java之Springcloud Gateway內(nèi)置路由案例講解,本篇文章通過簡(jiǎn)要的案例,講解了該項(xiàng)技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下
    2021-08-08
  • java中String.intern()方法功能介紹

    java中String.intern()方法功能介紹

    這篇文章主要介紹了java中String.intern()方法具有什么功能,主要包括String.intern原理,JDK6中String.intern()的相關(guān)知識(shí),本文給大家介紹的非常詳細(xì),需要的朋友可以參考下
    2022-06-06
  • SpringBoot整合Minio實(shí)現(xiàn)文件上傳和讀取功能

    SpringBoot整合Minio實(shí)現(xiàn)文件上傳和讀取功能

    最近有一個(gè)需求是關(guān)于視頻上傳播放的,需要設(shè)計(jì)一個(gè)方案,中間談到了Minio這個(gè)技術(shù),于是來學(xué)習(xí)一下,所以本文給大家介紹了SpringBoot整合Minio實(shí)現(xiàn)文件上傳和讀取功能,文中有詳細(xì)的代碼示例供大家參考,需要的朋友可以參考下
    2024-07-07
  • Java 抽象類定義與方法實(shí)例詳解

    Java 抽象類定義與方法實(shí)例詳解

    這篇文章主要介紹了java 抽象類與接口的區(qū)別介紹的相關(guān)資料,需要的朋友可以參考下...
    2017-04-04
  • SpringBoot使用Editor.md構(gòu)建Markdown富文本編輯器示例

    SpringBoot使用Editor.md構(gòu)建Markdown富文本編輯器示例

    這篇文章主要介紹了SpringBoot使用Editor.md構(gòu)建Markdown富文本編輯器示例,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2018-03-03
  • SpringBoot中yml多環(huán)境配置的3種方法

    SpringBoot中yml多環(huán)境配置的3種方法

    這篇文章主要給大家介紹了SpringBoot中yml多環(huán)境配置的3種方法,文中有詳細(xì)的代碼示例供大家參考,對(duì)大家的學(xué)習(xí)或工作有一定的幫助,需要的朋友可以參考下
    2023-10-10

最新評(píng)論