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

Spring?Boot常用功能Profile詳解

 更新時間:2022年07月15日 09:27:57   作者:lhf2112  
SpringBootProfile是一個很常用的功能,我們可以通過為開發(fā)/測試/生產(chǎn)環(huán)境配置不同的profile來實現(xiàn)配置隔離,那么在SpringBoot項目中是如何實現(xiàn)profile功能的呢

入口

相關(guān)邏輯的入口是listener類:ConfigFileApplicationListener,當(dāng)容器廣播器觸發(fā)ApplicationEnvironmentPreparedEvent事件時,ConfigFileApplicationListener會收到廣播器的通知,進而執(zhí)行onApplicationEnvironmentPreparedEvent方法

入口處代碼:

	@Override
	public void onApplicationEvent(ApplicationEvent event) {
		if (event instanceof ApplicationEnvironmentPreparedEvent) {
			onApplicationEnvironmentPreparedEvent((ApplicationEnvironmentPreparedEvent) event);
		}
		if (event instanceof ApplicationPreparedEvent) {
			onApplicationPreparedEvent(event);
		}
	}

接下來onApplicationEnvironmentPreparedEvent方法會加載容器中的EnvironmentPostProcessor并進行遍歷,調(diào)用他們的postProcessEnvironment方法,我們可以看一下此時的PostProcessor有哪些:

我們發(fā)現(xiàn)ConfigFileApplicationListener本身也是其中一個PostProcessor :)

我們直接進入ConfigFileApplicationListener的postProcessEnvironment方法,它會調(diào)用一個addPropertySources方法

	protected void addPropertySources(ConfigurableEnvironment environment, ResourceLoader resourceLoader) {
		RandomValuePropertySource.addToEnvironment(environment);
		new Loader(environment, resourceLoader).load();
	}

隨機屬性值部分暫且不表,我們看下loader.load方法

		public void load() {
			this.profiles = new LinkedList<>();
			this.processedProfiles = new LinkedList<>();
			this.activatedProfiles = false;
			this.loaded = new LinkedHashMap<>();
			initializeProfiles();
			while (!this.profiles.isEmpty()) {
				Profile profile = this.profiles.poll();
				if (profile != null && !profile.isDefaultProfile()) {
					addProfileToEnvironment(profile.getName());
				}
				load(profile, this::getPositiveProfileFilter, addToLoaded(MutablePropertySources::addLast, false));
				this.processedProfiles.add(profile);
			}
			resetEnvironmentProfiles(this.processedProfiles);
			load(null, this::getNegativeProfileFilter, addToLoaded(MutablePropertySources::addFirst, true));
			addLoadedPropertySources();
		}

load方法的重點邏輯-initializeProfiles()

private void initializeProfiles() {
	// The default profile for these purposes is represented as null. We add it
	// first so that it is processed first and has lowest priority.
	this.profiles.add(null);
	Set<Profile> activatedViaProperty = getProfilesActivatedViaProperty();
	this.profiles.addAll(getOtherActiveProfiles(activatedViaProperty));
	// Any pre-existing active profiles set via property sources (e.g.
	// System properties) take precedence over those added in config files.
	addActiveProfiles(activatedViaProperty);
	if (this.profiles.size() == 1) { // only has null profile
		for (String defaultProfileName : this.environment.getDefaultProfiles()) {
			Profile defaultProfile = new Profile(defaultProfileName, true);
			this.profiles.add(defaultProfile);
		}
	}
}

add(null) 可以處理application.properties/yml,接下來getProfilesActivatedViaProperty方法會從spring.profiles.active和spring.profiles.include配置中讀取激活的profile~(這兩者也是相對常用的配置);再接下來會判斷profiles大小是否為1,是的話會添加一個default profile,如圖所示:

這也解釋了為什么spring.profiles.default必須定義在其他屬性源(命令行啟動參數(shù)),因為這時候分散文件屬性元還沒有被解析到!

回到load方法,如果profiles不為空,就會進行while遍歷,對其調(diào)用另外一個load方法:

(load-number2方法):

		private void load(Profile profile, DocumentFilterFactory filterFactory, DocumentConsumer consumer) {
			getSearchLocations().forEach((location) -> {
				boolean isFolder = location.endsWith("/");
				Set<String> names = isFolder ? getSearchNames() : NO_SEARCH_NAMES;
				names.forEach((name) -> load(location, name, profile, filterFactory, consumer));
			});
		}

我們可以看到還會調(diào)用到另一個load方法

(load-number3方法):

private void load(String location, String name, Profile profile, DocumentFilterFactory filterFactory,
		DocumentConsumer consumer) {
	if (!StringUtils.hasText(name)) {
		for (PropertySourceLoader loader : this.propertySourceLoaders) {
			if (canLoadFileExtension(loader, location)) {
				load(loader, location, profile, filterFactory.getDocumentFilter(profile), consumer);
				return;
			}
		}
	}
	Set<String> processed = new HashSet<>();
	for (PropertySourceLoader loader : this.propertySourceLoaders) {
		for (String fileExtension : loader.getFileExtensions()) {
			if (processed.add(fileExtension)) {
				loadForFileExtension(loader, location + name, "." + fileExtension, profile, filterFactory,
						consumer);
			}
		}
	}
}

這里的propertySourceLoaders包括:

是不是很熟悉?這就是properties和yaml分別對應(yīng)的PropertySourceLoader~

下面代碼會調(diào)用loadForFileExtension方法,而這個方法又會調(diào)用新的load方法(??):

(load-number4方法):

private void load(PropertySourceLoader loader, String location, Profile profile, DocumentFilter filter,
		DocumentConsumer consumer) {
	try {
		Resource resource = this.resourceLoader.getResource(location);
		if (resource == null || !resource.exists()) {
			if (this.logger.isTraceEnabled()) {
				StringBuilder description = getDescription("Skipped missing config ", location, resource,
						profile);
				this.logger.trace(description);
			}
			return;
		}
		if (!StringUtils.hasText(StringUtils.getFilenameExtension(resource.getFilename()))) {
			if (this.logger.isTraceEnabled()) {
				StringBuilder description = getDescription("Skipped empty config extension ", location,
						resource, profile);
				this.logger.trace(description);
			}
			return;
		}
		String name = "applicationConfig: [" + location + "]";
		List<Document> documents = loadDocuments(loader, name, resource);
		if (CollectionUtils.isEmpty(documents)) {
			if (this.logger.isTraceEnabled()) {
				StringBuilder description = getDescription("Skipped unloaded config ", location, resource,
						profile);
				this.logger.trace(description);
			}
			return;
		}
		List<Document> loaded = new ArrayList<>();
		for (Document document : documents) {
			if (filter.match(document)) {
				addActiveProfiles(document.getActiveProfiles());
				addIncludedProfiles(document.getIncludeProfiles());
				loaded.add(document);
			}
		}
		Collections.reverse(loaded);
		if (!loaded.isEmpty()) {
			loaded.forEach((document) -> consumer.accept(profile, document));
			if (this.logger.isDebugEnabled()) {
				StringBuilder description = getDescription("Loaded config file ", location, resource, profile);
				this.logger.debug(description);
			}
		}
	}
	catch (Exception ex) {
		throw new IllegalStateException("Failed to load property " + "source from location '" + location + "'",
				ex);
	}
}

這個方法會讀取application-profile.properties/yaml文件,并加載文件內(nèi)激活的profile(如果有的話)

到這里已經(jīng)讀取到了所有的配置信息,主邏輯大概結(jié)束了,還差最后一個步驟:addLoadedPropertySources:

		private void addLoadedPropertySources() {
			MutablePropertySources destination = this.environment.getPropertySources();
			List<MutablePropertySources> loaded = new ArrayList<>(this.loaded.values());
			Collections.reverse(loaded);
			String lastAdded = null;
			Set<String> added = new HashSet<>();
			for (MutablePropertySources sources : loaded) {
				for (PropertySource<?> source : sources) {
					if (added.add(source.getName())) {
						addLoadedPropertySource(destination, lastAdded, source);
						lastAdded = source.getName();
					}
				}
			}
		}

這里會將所有屬性加入到“destination”,即environment.getPropertySources(),到這里,加載配置屬性的邏輯就完成了。

到此這篇關(guān)于Spring Boot常用功能Profile詳解的文章就介紹到這了,更多相關(guān)Spring Boot Profile內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Java漏桶算法的簡單代碼實例

    Java漏桶算法的簡單代碼實例

    這篇文章主要介紹了Java漏桶算法的簡單代碼實例,漏桶算法的意義在于能夠平滑請求,不給下游服務(wù)造成過大壓力,特別適用于突發(fā)流量或者定時任務(wù)拉取大量數(shù)據(jù)時,需要處理大量數(shù)據(jù)或者請求的場景,需要的朋友可以參考下
    2024-01-01
  • MyBatis的9種動態(tài)標簽詳解

    MyBatis的9種動態(tài)標簽詳解

    大家好,本篇文章主要講的是MyBatis的9種動態(tài)標簽詳解,感興趣的同學(xué)趕快來看一看吧,感興趣的同學(xué)趕快來看一看吧
    2021-12-12
  • Springcloud GateWay網(wǎng)關(guān)配置過程圖解

    Springcloud GateWay網(wǎng)關(guān)配置過程圖解

    這篇文章主要介紹了Springcloud GateWay網(wǎng)關(guān)配置過程圖解,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2020-12-12
  • 基于紅黑樹插入操作原理及java實現(xiàn)方法(分享)

    基于紅黑樹插入操作原理及java實現(xiàn)方法(分享)

    下面小編就為大家分享一篇基于紅黑樹插入操作原理及java實現(xiàn)方法,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2017-12-12
  • SpringBoot使用WebSocket實現(xiàn)前后端交互的操作方法

    SpringBoot使用WebSocket實現(xiàn)前后端交互的操作方法

    springboot使用websocket有兩種方式,一種是實現(xiàn)簡單的websocket,另外一種是實現(xiàn)STOMP協(xié)議,本篇講述如何使用springboot實現(xiàn)簡單的websocket,需要的朋友可以參考下
    2022-04-04
  • Spring5中SpringWebContext方法過時的解決方案

    Spring5中SpringWebContext方法過時的解決方案

    這篇文章主要介紹了Spring5中SpringWebContext方法過時的解決方案,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-01-01
  • SpringBoot配置Redis實現(xiàn)保存獲取和刪除數(shù)據(jù)

    SpringBoot配置Redis實現(xiàn)保存獲取和刪除數(shù)據(jù)

    本文主要介紹了SpringBoot配置Redis實現(xiàn)保存獲取和刪除數(shù)據(jù),文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,感興趣的小伙伴們可以參考一下
    2021-06-06
  • servlet的常見注冊方式總結(jié)

    servlet的常見注冊方式總結(jié)

    servlet大家都不陌生,當(dāng)開發(fā)?Web?應(yīng)用程序時,注冊?Servlet?是一個常見的任務(wù),本文將介紹一些常見的?Servlet?注冊方法,希望對大家有所幫助
    2023-10-10
  • idea中如何配置tomcat

    idea中如何配置tomcat

    這篇文章主要介紹了idea中如何配置tomcat問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2023-03-03
  • Java數(shù)據(jù)結(jié)構(gòu)中圖的進階詳解

    Java數(shù)據(jù)結(jié)構(gòu)中圖的進階詳解

    在Java學(xué)習(xí)與應(yīng)用中,數(shù)據(jù)結(jié)構(gòu)無疑是每個人都要接觸的難點,為了更好的學(xué)習(xí)數(shù)據(jù)結(jié)構(gòu)這一塊內(nèi)容,用圖來理解便是最好的方式,讓我們一起來了解本篇內(nèi)容圖的進階
    2022-01-01

最新評論