日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

springboot 读取application.properties流程

發布時間:2025/3/19 编程问答 25 豆豆
生活随笔 收集整理的這篇文章主要介紹了 springboot 读取application.properties流程 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

一、application.properties配置如下,當然也可以配置YAML。

application-dev.properties

server.port=8110 spring.application.name=newday-servicespring.jpa.show-sql=true spring.jpa.properties.hibernate.format_sql=truelogging.level.org.hibernate.type.descriptor.sql.BasicBinder=tracespring.datasource.primary.jdbc-url=jdbc:mysql://rm-wz96s5izji5099uz13o.mysql.rds.aliyuncs.com:3306/xfz178_com?serverTimezone=UTC&characterEncoding=utf8## test2 database #spring.datasource.localdb.jdbc-url=jdbc:mysql://localhost:3306/test?serverTimezone=UTC&characterEncoding=utf8 #spring.datasource.localdb.username=root #spring.datasource.localdb.password=123456 #spring.datasource.localdb.driverClassName=com.mysql.cj.jdbc.Driver#logging.file.name=./logs/newday-service.log #日志級別 #logging.file.level.ROOT=DEBUG #logging.config=classpath:log4j2.xml logging.config=classpath:logback-spring.xmlredisson.address = redis://127.0.0.1:6379 redisson.password =#people.beanfactory = PeopleSpringFactory people.beanfactory = PeopleBeanFactory

?二、加載流程

? ?1.SpringApplication在Run時,會先預加載環境,即是讀取各種配置到環境對象中,然后會廣播

ApplicationEnvironmentPreparedEvent消息。 org.springframework.boot.context.event.environmentPrepared @Overridepublic void environmentPrepared(ConfigurableEnvironment environment) {this.initialMulticaster.multicastEvent(new ApplicationEnvironmentPreparedEvent(this.application, this.args, environment));}

2.org.springframework.boot.context.config.ConfigFileApplicationListener.onApplicationEvent會被觸發調用,因為其實現了ApplicationListener會接收事件。

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

?3.然后會調用到ConfigFileApplicationListener.postProcessEnvironment,去加載屬性配置文件到環境對象。

public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) {addPropertySources(environment, application.getResourceLoader());}protected void addPropertySources(ConfigurableEnvironment environment, ResourceLoader resourceLoader) {RandomValuePropertySource.addToEnvironment(environment);new Loader(environment, resourceLoader).load();}

4.在ConfigFileApplicationListener.Loader的內部類中,會初始化兩個資源配置文件加載器。properties,yaml

?5.在loader.load方法中會初始化所有的profile,然后再搜索可用的PROFILE配置文件。

void load() {FilteredPropertySource.apply(this.environment, DEFAULT_PROPERTIES, LOAD_FILTERED_PROPERTY,(defaultProperties) -> {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 (isDefaultProfile(profile)) {addProfileToEnvironment(profile.getName());}load(profile, this::getPositiveProfileFilter,addToLoaded(MutablePropertySources::addLast, false));this.processedProfiles.add(profile);}load(null, this::getNegativeProfileFilter, addToLoaded(MutablePropertySources::addFirst, true));addLoadedPropertySources();applyActiveProfiles(defaultProperties);});}

6.?第二個load方法

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

最終讀取到的搜索路徑為:

?獲取搜索文件名,這里注意,如果環境對象中有CONFIG_NAME_PROPERT(spring.config.name)這個配置屬性,前面的bootStrap.properties就是通過前一個BootstrapApplicationListener加載的listener,這個對象會在監聽到環境準備事件時,設置spring.config.name為bootStrap,然后由當前這個listener來加載配置,則搜索這個文件名,否則搜索默認文件名DEFAULT_NAMES(application):

private Set<String> getSearchNames() {if (this.environment.containsProperty(CONFIG_NAME_PROPERTY)) {String property = this.environment.getProperty(CONFIG_NAME_PROPERTY);Set<String> names = asResolvedSet(property, null);names.forEach(this::assertValidConfigName);return names;}return asResolvedSet(ConfigFileApplicationListener.this.names, DEFAULT_NAMES);}

7.接著調用第三個load方法,搜索不同目錄下的配置文件。

private void load(String location, String name, Profile profile, DocumentFilterFactory filterFactory,DocumentConsumer consumer) {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);}}}}

8.接著調用第四個load,加載指定擴展名的文件。

private void loadForFileExtension(PropertySourceLoader loader, String prefix, String fileExtension,Profile profile, DocumentFilterFactory filterFactory, DocumentConsumer consumer) {DocumentFilter defaultFilter = filterFactory.getDocumentFilter(null);DocumentFilter profileFilter = filterFactory.getDocumentFilter(profile);if (profile != null) {// Try profile-specific file & profile section in profile file (gh-340)String profileSpecificFile = prefix + "-" + profile + fileExtension;load(loader, profileSpecificFile, profile, defaultFilter, consumer);load(loader, profileSpecificFile, profile, profileFilter, consumer);// Try profile specific sections in files we've already processedfor (Profile processedProfile : this.processedProfiles) {if (processedProfile != null) {String previouslyLoaded = prefix + "-" + processedProfile + fileExtension;load(loader, previouslyLoaded, profile, profileFilter, consumer);}}}// Also try the profile-specific section (if any) of the normal fileload(loader, prefix + fileExtension, profile, profileFilter, consumer);}

9.接著調用第五個load方法,真正去目錄搜索指定文件名和后綴的文件,然后加載到文檔。

private void load(PropertySourceLoader loader, String location, Profile profile, DocumentFilter filter,DocumentConsumer consumer) {Resource[] resources = getResources(location);for (Resource resource : resources) {try {String name = "applicationConfig: [" + getLocationName(location, resource) + "]";List<Document> documents = loadDocuments(loader, name, resource);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);}}}}}

10.在加載文檔時最后會轉換文檔 。

private List<Document> asDocuments(List<PropertySource<?>> loaded) {if (loaded == null) {return Collections.emptyList();}return loaded.stream().map((propertySource) -> {Binder binder = new Binder(ConfigurationPropertySources.from(propertySource),this.placeholdersResolver);String[] profiles = binder.bind("spring.profiles", STRING_ARRAY).orElse(null);Set<Profile> activeProfiles = getProfiles(binder, ACTIVE_PROFILES_PROPERTY);Set<Profile> includeProfiles = getProfiles(binder, INCLUDE_PROFILES_PROPERTY);return new Document(propertySource, profiles, activeProfiles, includeProfiles);}).collect(Collectors.toList());}

11.getProfiles(binder, ACTIVE_PROFILES_PROPERTY)這句話,會去從當前讀取到的配置文件屬性中查找spring.profiles.active屬性,然后設置到環境變量。
? ? ? ? 這個綁定方法和@configurationProperties中的對象屬性綁定原理一致,都是從資源屬性列表中逐個資源文件中搜索名稱為name的配置。像這里就是spring.profile.active,spring.profile.include

private Set<Profile> getProfiles(Binder binder, String name) {return binder.bind(name, STRING_ARRAY).map(this::asProfileSet).orElse(Collections.emptySet());}

?注意這里的binder不是當前環境變量的binder,而是當前搜索到的配置文件動態生成的BINDER.

Binder binder = new Binder(ConfigurationPropertySources.from(propertySource),this.placeholdersResolver);

?現在我們讀取application.properties的配置數據了,只有一個。

?12.然后我們接著最后一個load代碼,當讀取到默認的配置文檔后,會再次加載激活和包含的profile配置。

addActiveProfiles(document.getActiveProfiles());addIncludedProfiles(document.getIncludeProfiles());loaded.add(document); void addActiveProfiles(Set<Profile> profiles) {this.profiles.addAll(profiles);this.activatedProfiles = true;removeUnprocessedDefaultProfiles();}

此時我們可以看到,已經把dev的profile也加進來了。

?13.最后會把加載到的文檔 配置屬性回調給消費者函數。

loaded.forEach((document) -> consumer.accept(profile, document)); ConfigFileApplicationListener.addToLoaded就是消費的回調。 private DocumentConsumer addToLoaded(BiConsumer<MutablePropertySources, PropertySource<?>> addMethod,boolean checkForExisting) {return (profile, document) -> {if (checkForExisting) {for (MutablePropertySources merged : this.loaded.values()) {if (merged.contains(document.getPropertySource().getName())) {return;}}}MutablePropertySources merged = this.loaded.computeIfAbsent(profile,(k) -> new MutablePropertySources());addMethod.accept(merged, document.getPropertySource());};}

這里面的addMethod又是一個回調方法,最終調用到

MutablePropertySources.addLast將這個資源文件對象加載到環境對象的propertList屬性中。

設置兩個回調的地方在第一個load中,可以找到第一個看代碼。

load(profile, this::getPositiveProfileFilter,addToLoaded(MutablePropertySources::addLast, false)); public void addLast(PropertySource<?> propertySource) {synchronized (this.propertySourceList) {removeIfPresent(propertySource);this.propertySourceList.add(propertySource);}}

?最終屬性數據存儲在內部類loader

private Map<Profile, MutablePropertySources> loaded 屬性中。

14.然后我們再回到第一個load函數,他會不斷循環所有的profiles,因為之前已經往這個profile列表中加上dev,所以會再次循環加載dev的profile配置,流程一樣。

while (!this.profiles.isEmpty()) {Profile profile = this.profiles.poll();if (isDefaultProfile(profile)) {addProfileToEnvironment(profile.getName());}load(profile, this::getPositiveProfileFilter,addToLoaded(MutablePropertySources::addLast, false));this.processedProfiles.add(profile);}

?這是加載dev的profile的配置屬性列表。

?然后回調,就會把dev的文檔生成資源屬性文件添加到loaded列表。

?15.最后會調用addLoadedPropertySources把加載成功的配置屬性添加到環境對象的propertySources中。

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

加載前

?加載后

我們可以看到,是加載到尾部,這也證明了配置文件的優先級最低。同時我們可以看到dev的配置文件是在默認之前。所以會覆蓋默認的。

注意上面添加代碼,有對loaded作倒序處理。

Collections.reverse(loaded);

至此,配置文件屬性加載完畢。?

總結

以上是生活随笔為你收集整理的springboot 读取application.properties流程的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

主站蜘蛛池模板: 尤物视频在线观看免费 | 国产奶水涨喷在线播放 | 亚洲女人视频 | 尤果网福利视频在线观看 | 日韩电影网址 | av网址导航 | 亚洲成在线 | 又大又粗又爽18禁免费看 | 自拍三级 | 久久久精品影视 | 国产日产精品一区二区三区 | 国产a级片免费看 | 久久久噜噜噜久久中文字幕色伊伊 | 蜜臀少妇久久久久久久高潮 | 免费看美女隐私网站 | 日韩黄色网 | 天天5g天天爽免费观看 | 伊人成人久久 | 欧美交 | 国产爽爽爽 | 麻豆av免费观看 | 欧美日韩精品国产 | 国产精品福利一区 | 一级空姐毛片 | 国产一级淫片a | 欧美日韩色图片 | 国产人妻一区二区 | 亚洲精品亚洲人成人网 | 国产av一区二区三区 | 欧美操穴 | 欧美自拍偷拍一区 | 久久中文字幕无码 | 欧美精品一区二区蜜臀亚洲 | 久久中文字幕av | 亚洲一区二区精品在线观看 | 黄色在线网 | 欧美日韩不卡视频 | 99在线视频免费观看 | 亚洲精品久久久久中文字幕二区 | 99在线视频播放 | 国产精品人妖 | 国产不卡精品视频 | 91欧美激情一区二区三区成人 | 天天色影网 | 最新中文字幕第一页 | 噜噜色图 | 久久99热这里只频精品6学生 | 成人夜夜 | 色播五月激情 | 国产激情影院 | youjizz.com中国| 别揉我奶头一区二区三区 | 欧美日韩视频在线播放 | 黄色片网站在线播放 | 亚洲婷婷综合网 | 欧美美女在线观看 | 欧美黄色大片视频 | 红猫大本营在线观看的 | 不卡精品视频 | 粉色视频免费观看 | 中文字幕一区二区三区四区 | 91丨porny丨对白| 午夜中出| 日韩精品中文在线 | 少妇熟女一区二区 | 视色网 | 日韩中文字幕在线观看 | 我和公激情中文字幕 | 久久国产欧美日韩精品 | 欧美综合一区二区 | 亚洲av毛片基地 | 在线高清观看免费观看 | 永久视频 | 色鬼综合 | 欧美你懂得| 国产嫩草视频 | 欧美大白屁股 | 男男play呻吟动漫网站 | 精品欧美黑人一区二区三区 | 久久久久亚洲av无码网站 | 午夜一区二区三区四区 | 91av国产精品 | 夜夜涩| 欧美三级网站在线观看 | 日韩精品一区二区三区网站 | 精品久久久久中文慕人妻 | 色婷婷精品久久二区二区密 | 久艹在线 | 久热超碰 | 久久视频免费看 | 韩国黄色精品 | 熟女少妇一区二区三区 | 色妞www精品视频 | 欧美成人一区二区在线 | 亚洲欧美久久 | 91资源站 | 双性娇喘浑圆奶水h男男漫画 | 国产一区二区三区视频在线观看 | 日本精品一区二区在线观看 |