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

歡迎訪問 生活随笔!

生活随笔

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

编程问答

spring boot实战(第六篇)加载application资源文件源码分析

發布時間:2025/3/21 编程问答 14 豆豆
生活随笔 收集整理的這篇文章主要介紹了 spring boot实战(第六篇)加载application资源文件源码分析 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

前言

在上一篇中了解了spring配置資源的加載過程,本篇在此基礎上學習spring boot如何默認加載application.xml等文件信息的。

?

?

ConfigFileApplicationListener

在spring boot實戰(第三篇)事件監聽源碼分析中可知在構造SpringApplication時加載相關的監聽器,其中存在一個監聽器ConfigFileApplicationListener,其定義如下:

[html]?view plain?copy

  • public?class?ConfigFileApplicationListener?implements??
  • ????????ApplicationListener<ApplicationEvent>,?Ordered?{??
  • @Override??
  • ????public?void?onApplicationEvent(ApplicationEvent?event)?{??
  • ????????if?(event?instanceof?ApplicationEnvironmentPreparedEvent)?{??
  • ????????????onApplicationEnvironmentPreparedEvent((ApplicationEnvironmentPreparedEvent)?event);??
  • ????????}??
  • ????????if?(event?instanceof?ApplicationPreparedEvent)?{??
  • ????????????onApplicationPreparedEvent((ApplicationPreparedEvent)?event);??
  • ????????}??
  • ????}??
  • ???
  • }??

  • 監聽ApplicationEvent事件,在觸發所有其子類以及本身事件時會執行其onApplicationEvent方法。在執行

    [html]?view plain?copy

  • for?(SpringApplicationRunListener?runListener?:?runListeners)?{??
  • ????runListener.environmentPrepared(environment);??
  • }??
  • 時會觸發到

    [html]?view plain?copy

  • if?(event?instanceof?ApplicationEnvironmentPreparedEvent)?{??
  • ????????????onApplicationEnvironmentPreparedEvent((ApplicationEnvironmentPreparedEvent)?event);??
  • ????????}??
  • 中;

    ?

    [html]?view plain?copy

  • private?void?onApplicationEnvironmentPreparedEvent(??
  • ????????????ApplicationEnvironmentPreparedEvent?event)?{??
  • ????????Environment?environment?=?event.getEnvironment();??
  • ????????if?(environment?instanceof?ConfigurableEnvironment)?{??
  • ????????????onApplicationEnvironmentPreparedEvent((ConfigurableEnvironment)?environment,??
  • ????????????????????event.getSpringApplication());??
  • ????????}??
  • ????}??
  • ?

    在上一篇中可以知道enviroment為StandardServletEnvironment實例,因此執行onApplicationEnvironmentPreparedEvent方法

    ?

    [html]?view plain?copy

  • private?void?onApplicationEnvironmentPreparedEvent(??
  • ????????????ConfigurableEnvironment?environment,?SpringApplication?application)?{??
  • ????????addPropertySources(environment,?application.getResourceLoader());??
  • ????????bindToSpringApplication(environment,?application);??
  • ????}??
  • 首先來看addPropertySources相關信息

    ?

    [html]?view plain?copy

  • protected?void?addPropertySources(ConfigurableEnvironment?environment,??
  • ????????????ResourceLoader?resourceLoader)?{??
  • ????????RandomValuePropertySource.addToEnvironment(environment);??
  • ????????try?{??
  • ????????????new?Loader(environment,?resourceLoader).load();??
  • ????????}??
  • ????????catch?(IOException?ex)?{??
  • ????????????throw?new?IllegalStateException("Unable?to?load?configuration?files",?ex);??
  • ????????}??
  • ????}??
  • ?

    RandomValuePropertySource.addToEnvironment(environment)將隨機方法放入到PropertySources中

    ?

    [html]?view plain?copy

  • public?static?void?addToEnvironment(ConfigurableEnvironment?environment)?{??
  • ????????environment.getPropertySources().addAfter(??
  • ????????????????StandardEnvironment.SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME,??
  • ????????????????new?RandomValuePropertySource("random"));??
  • ????????logger.trace("RandomValuePropertySource?add?to?Environment");??
  • ????}??

  • 如何從Random中獲取值是需要看getProperty方法:

    [html]?view plain?copy

  • public?Object?getProperty(String?name)?{??
  • ????????if?(!name.startsWith("random."))?{??
  • ????????????return?null;??
  • ????????}??
  • ????????if?(logger.isTraceEnabled())?{??
  • ????????????logger.trace("Generating?random?property?for?'"?+?name?+?"'");??
  • ????????}??
  • ????????if?(name.endsWith("int"))?{??
  • ????????????return?getSource().nextInt();??
  • ????????}??
  • ????????if?(name.startsWith("random.long"))?{??
  • ????????????return?getSource().nextLong();??
  • ????????}??
  • ????????if?(name.startsWith("random.int")?&&?name.length()?>?"random.int".length()?+?1)?{??
  • ????????????String?range?=?name.substring("random.int".length()?+?1);??
  • ????????????range?=?range.substring(0,?range.length()?-?1);??
  • ????????????return?getNextInRange(range);??
  • ????????}??
  • ????????byte[]?bytes?=?new?byte[32];??
  • ????????getSource().nextBytes(bytes);??
  • ????????return?DigestUtils.md5DigestAsHex(bytes);??
  • ????}??

  • 其中的getSource()表示Random類。

    接下來看

    [html]?view plain?copy

  • new?Loader(environment,?resourceLoader).load()??
  • 看load方法

    [html]?view plain?copy

  • public?void?load()?throws?IOException?{??
  • ????????????...//處理profiles信息??
  • ??????????????
  • ????????????while?(!this.profiles.isEmpty())?{??
  • ????????????????String?profile?=?this.profiles.poll();??
  • ????????????????for?(String?location?:?getSearchLocations())?{??
  • ????????????????????if?(!location.endsWith("/"))?{??
  • ????????????????????????//?location?is?a?filename?already,?so?don't?search?for?more??
  • ????????????????????????//?filenames??
  • ????????????????????????load(location,?null,?profile);??
  • ????????????????????}??
  • ????????????????????else?{??
  • ????????????????????????for?(String?name?:?getSearchNames())?{??
  • ????????????????????????????load(location,?name,?profile);??
  • ????????????????????????}??
  • ????????????????????}??
  • ????????????????}??
  • ????????????}??
  • ??
  • ????????????addConfigurationProperties(this.propertiesLoader.getPropertySources());??
  • ????????}??

  • 看getSearchLocations()方法

    ?

    [html]?view plain?copy

  • private?Set<String>?getSearchLocations()?{??
  • ????????????Set<String>?locations?=?new?LinkedHashSet<String>();??
  • ????????????//?User-configured?settings?take?precedence,?so?we?do?them?first??
  • ????????????if?(this.environment.containsProperty(CONFIG_LOCATION_PROPERTY))?{??
  • ????????????????for?(String?path?:?asResolvedSet(??
  • ????????????????????????this.environment.getProperty(CONFIG_LOCATION_PROPERTY),?null))?{??
  • ????????????????????if?(!path.contains("$"))?{??
  • ????????????????????????if?(!path.contains(":"))?{??
  • ????????????????????????????path?=?"file:"?+?path;??
  • ????????????????????????}??
  • ????????????????????????path?=?StringUtils.cleanPath(path);??
  • ????????????????????}??
  • ????????????????????locations.add(path);??
  • ????????????????}??
  • ????????????}??
  • ????????????locations.addAll(asResolvedSet(??
  • ????????????????????ConfigFileApplicationListener.this.searchLocations,??
  • ????????????????????DEFAULT_SEARCH_LOCATIONS));??
  • ????????????return?locations;??
  • ????????}??

  • 首先看CONFIG_LOCATION_PROPERTY(spring.config.location)是否存在配置,無則走默認配置路徑DEFAULT_SEARCH_LOCATIONS(classpath:/,classpath:/config/,file:./,file:./config/)

    ?

    繼續來看getSearchNames()方法

    ?

    [html]?view plain?copy

  • private?Set<String>?getSearchNames()?{??
  • ????????if?(this.environment.containsProperty(CONFIG_NAME_PROPERTY))?{??
  • ????????????return?asResolvedSet(this.environment.getProperty(CONFIG_NAME_PROPERTY),??
  • ????????????????????null);??
  • ????????}??
  • ????????return?asResolvedSet(ConfigFileApplicationListener.this.names,?DEFAULT_NAMES);??
  • ????}??
  • 優先看CONFIG_NAME_PROPERTY(spring.config.name)配置,否則走DEFAULT_NAMES(application)

    ?

    解析完路徑和配置文件名以后,將開始判斷路徑+名稱組合是否存在 ?執行load(...)方法

    [html]?view plain?copy

  • private?void?load(String?location,?String?name,?String?profile)??
  • ????????????????throws?IOException?{??
  • ????????????String?group?=?"profile="?+?(profile?==?null???""?:?profile);??
  • ????????????if?(!StringUtils.hasText(name))?{??
  • ????????????????//?Try?to?load?directly?from?the?location??
  • ????????????????loadIntoGroup(group,?location,?profile);??
  • ????????????}??
  • ????????????else?{??
  • ????????????????//?Search?for?a?file?with?the?given?name??
  • ????????????????for?(String?ext?:?this.propertiesLoader.getAllFileExtensions())?{??
  • ????????????????????if?(profile?!=?null)?{??
  • ????????????????????????//?Try?the?profile?specific?file??
  • ????????????????????????loadIntoGroup(group,?location?+?name?+?"-"?+?profile?+?"."?+?ext,??
  • ????????????????????????????????null);??
  • ????????????????????????//?Sometimes?people?put?"spring.profiles:?dev"?in??
  • ????????????????????????//?application-dev.yml?(gh-340).?Arguably?we?should?try?and?error??
  • ????????????????????????//?out?on?that,?but?we?can?be?kind?and?load?it?anyway.??
  • ????????????????????????loadIntoGroup(group,?location?+?name?+?"-"?+?profile?+?"."?+?ext,??
  • ????????????????????????????????profile);??
  • ????????????????????}??
  • ????????????????????//?Also?try?the?profile?specific?section?(if?any)?of?the?normal?file??
  • ????????????????????loadIntoGroup(group,?location?+?name?+?"."?+?ext,?profile);??
  • ????????????????}??
  • ????????????}??
  • ????????}??
  • this.propertiesLoader.getAllFileExtensions()方法獲取文件后綴

    ?

    [html]?view plain?copy

  • public?Set<String>?getAllFileExtensions()?{??
  • ????????Set<String>?fileExtensions?=?new?HashSet<String>();??
  • ????????for?(PropertySourceLoader?loader?:?this.loaders)?{??
  • ????????????fileExtensions.addAll(Arrays.asList(loader.getFileExtensions()));??
  • ????????}??
  • ????????return?fileExtensions;??
  • ????}??

  • loader.getFileExtensions()獲取所有支持的文件后綴,其中loader在執行load方法時實例化

    ?

    [html]?view plain?copy

  • public?void?load()?throws?IOException?{??
  • ????????????this.propertiesLoader?=?new?PropertySourcesLoader();??
  • ...}??
  • 調用其構造方法

    [html]?view plain?copy

  • public?PropertySourcesLoader(MutablePropertySources?propertySources)?{??
  • ????Assert.notNull(propertySources,?"PropertySources?must?not?be?null");??
  • ????this.propertySources?=?propertySources;??
  • ????this.loaders?=?SpringFactoriesLoader.loadFactories(PropertySourceLoader.class,??
  • ????????????null);??
  • }??
  • 可以看出this.loaders是由SpringFactoriesLoader.loadFactories(PropertySourceLoader.class,null)得到

    ?

    [html]?view plain?copy

  • public?static?<T>?List<T>?loadFactories(Class<T>?factoryClass,?ClassLoader?classLoader)?{??
  • ????Assert.notNull(factoryClass,?"'factoryClass'?must?not?be?null");??
  • ????ClassLoader?classLoaderToUse?=?classLoader;??
  • ????if?(classLoaderToUse?==?null)?{??
  • ????????classLoaderToUse?=?SpringFactoriesLoader.class.getClassLoader();??
  • ????}??
  • ????List<String>?factoryNames?=?loadFactoryNames(factoryClass,?classLoaderToUse);??
  • ????if?(logger.isTraceEnabled())?{??
  • ????????logger.trace("Loaded?["?+?factoryClass.getName()?+?"]?names:?"?+?factoryNames);??
  • ????}??
  • ????List<T>?result?=?new?ArrayList<T>(factoryNames.size());??
  • ????for?(String?factoryName?:?factoryNames)?{??
  • ????????result.add(instantiateFactory(factoryName,?factoryClass,?classLoaderToUse));??
  • ????}??
  • ????AnnotationAwareOrderComparator.sort(result);??
  • ????return?result;??
  • }??

  • 加載META-INF/spring.factories文件下對應內容

    [html]?view plain?copy

  • #?PropertySource?Loaders??
  • org.springframework.boot.env.PropertySourceLoader=\??
  • org.springframework.boot.env.PropertiesPropertySourceLoader,\??
  • org.springframework.boot.env.YamlPropertySourceLoader??
  • ?

    因此加載了PropertiesPropertySourceLoader以及YamlPropertySourceLoader類實例;

    • PropertiesPropertySourceLoader 支持文件后綴格式 "properties","xml"?

    [html]?view plain?copy

  • @Override??
  • ????public?String[]?getFileExtensions()?{??
  • ????????return?new?String[]?{?"properties",?"xml"?};??
  • ????}??
    • YamlPropertySourceLoader 支持文件后綴格式?"yml","yaml"

    [html]?view plain?copy

  • @Override??
  • ????public?String[]?getFileExtensions()?{??
  • ????????return?new?String[]?{?"yml",?"yaml"?};??
  • ????}??

  • 兩者覆寫的load方法實現如何處理資源為PropertySource對象。

    ?

    獲取完文件后綴后調用loadIntoGroup方法將資源信息轉化為PropertySource,其實質為調用PropertySourcesLoader中load方法

    [html]?view plain?copy

  • private?PropertySource<?>?loadIntoGroup(String?identifier,?String?location,??
  • ????????????????String?profile)?throws?IOException?{??
  • ????????????Resource?resource?=?this.resourceLoader.getResource(location);??
  • ????????????PropertySource<?>?propertySource?=?null;??
  • ????????????if?(resource?!=?null)?{??
  • ????????????????String?name?=?"applicationConfig:?["?+?location?+?"]";??
  • ????????????????String?group?=?"applicationConfig:?["?+?identifier?+?"]";??
  • ????????????????propertySource?=?this.propertiesLoader.load(resource,?group,?name,??
  • ????????????????????????profile);??
  • ????????????????if?(propertySource?!=?null)?{??
  • ????????????????????maybeActivateProfiles(propertySource??
  • ????????????????????????????.getProperty(ACTIVE_PROFILES_PROPERTY));??
  • ????????????????????addIncludeProfiles(propertySource??
  • ????????????????????????????.getProperty(INCLUDE_PROFILES_PROPERTY));??
  • ????????????????}??
  • ????????????}??
  • ????????????StringBuilder?msg?=?new?StringBuilder();??
  • ????????????msg.append(propertySource?==?null???"Skipped?"?:?"Loaded?");??
  • ????????????msg.append("config?file?");??
  • ????????????msg.append("'").append(location).append("'");??
  • ????????????if?(StringUtils.hasLength(profile))?{??
  • ????????????????msg.append("?for?profile"?+?profile);??
  • ????????????}??
  • ????????????if?(resource?==?null?||?!resource.exists())?{??
  • ????????????????msg.append("?resource?not?found");??
  • ????????????}??
  • ????????????this.debug.add(msg);??
  • ????????????return?propertySource;??
  • ????????}??

  • 最后調用addConfigurationProperties(this.propertiesLoader.getPropertySources())方法將解析過后的資源信息放置進Enviroment中propertySources屬性集合中

    [html]?view plain?copy

  • private?void?addConfigurationProperties(MutablePropertySources?sources)?{??
  • ????????????List<PropertySource<?>>?reorderedSources?=?new?ArrayList<PropertySource<?>>();??
  • ????????????for?(PropertySource<?>?item?:?sources)?{??
  • ????????????????reorderedSources.add(item);??
  • ????????????}??
  • ????????????//?Maybe?we?should?add?before?the?DEFAULT_PROPERTIES?if?it?exists???
  • ????????????this.environment.getPropertySources().addLast(??
  • ????????????????????new?ConfigurationPropertySources(reorderedSources));??
  • ????????}??


  • 至此 application.xml等文件的加載分析結束。

    ?

    時序圖

    簡單的畫了一下時序圖,可能和實際調用存在出入,僅作參考使用?


    ?

    總結

    以上是生活随笔為你收集整理的spring boot实战(第六篇)加载application资源文件源码分析的全部內容,希望文章能夠幫你解決所遇到的問題。

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

    主站蜘蛛池模板: 亚洲AV无码精品色毛片浪潮 | 亚洲精品资源在线 | 精品久久九九 | 成人午夜影院 | 亚洲系列中文字幕 | 国产又粗又黄又爽又硬的视频 | 综合色吧 | 久久理伦 | 男女瑟瑟视频 | 亚洲欧洲综合在线 | 美女黄视频网站 | а√在线中文网新版地址在线 | 天堂婷婷 | 日本一区二区欧美 | av色先锋 | 成人91| 免费午夜视频 | 爱爱视频免费网站 | 中文字幕高清av | 光棍影院av | 99re这里只有精品在线 | 国产夜色精品一区二区av | 久久国产视频网站 | 91日韩中文字幕 | 欧美一区三区二区在线观看 | 欧美午夜激情影院 | 在线视频久| 国产一区二区三区视频网站 | 国产91精品看黄网站在线观看 | 国产精品日韩专区 | 激情偷拍 | 日韩欧美高清片 | 五月综合在线 | 国产草草影院 | 日本午夜激情视频 | 欧美精品久久久久久久久 | 无码av天堂一区二区三区 | 99国产精品久久久久久久 | 精品国产av无码一区二区三区 | 欧美在线资源 | 国产做爰xxxⅹ性视频国 | 亚洲一级在线 | 日本黄视频网站 | 97在线播放免费观看 | 男男成人高潮片免费网站 | 国产精品无码毛片 | 69av一区二区三区 | 五月丁香| caopor在线视频 | 日韩精品视频免费看 | 97av视频 | 做爰视频毛片视频 | 亚洲欧美日韩第一页 | 国产视频播放 | 四虎成人精品永久免费av九九 | 午夜精品视频在线观看 | 日日骚网 | 欧美激情视频网址 | 99视频这里有精品 | 久久亚洲综合色图 | 欧美性爱精品在线 | 农村老熟妇乱子伦视频 | 灌篮高手全国大赛电影 | 插插插操操操 | 国产精品资源在线观看 | 欧美91视频| 人妻射精一区二区 | 一区二区视频免费看 | 性感美女黄色片 | 91嫩草欧美久久久九九九 | 伊人精品视频在线观看 | 黄色观看网站 | 久草资源福利 | 国产天天综合 | 久草热在线观看 | 最新国产精品自拍 | 日韩精品一区在线播放 | 超碰av在线播放 | 国产精品视频一区二区三区 | 免费观看一级视频 | 国产探花精品在线 | 亚洲欧美一二三 | 解开人妻的裙子猛烈进入 | 国产欧美一区二区在线观看 | 天堂俺去俺来也www久久婷婷 | 日韩免费一级片 | 色中文字幕在线观看 | 我们的2018中文免费看 | 亚洲人妻电影一区 | 国产精品午夜视频 | 裸体裸乳免费看 | 亚洲中文字幕无码一区 | 天天操bb | 色图自拍偷拍 | 精品视频网站 | 毛片基地免费 | 天天av天天操 | 久久毛片视频 | 岛国av中文字幕 |