日韩性视频-久久久蜜桃-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资源文件源码分析的全部內容,希望文章能夠幫你解決所遇到的問題。

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

    主站蜘蛛池模板: 少妇人妻一区 | 欧美九九九 | 日韩激情毛片 | 99久久精品免费看国产交换 | 国产精品资源 | 欧美日韩中文字幕 | 亚洲精品白浆高清久久久久久 | 亚洲自拍在线观看 | 日本69少妇 | 毛片在线免费观看视频 | 毛片av在线观看 | 147人体做爰大胆图片成人 | 穿情趣内衣被c到高潮视频 欧美性猛交xxxx黑人猛交 | 成年人在线观看视频网站 | 中文字幕一区二区三区久久久 | 欧美精品二区三区四区免费看视频 | 东北高大丰满bbbbzbbb | 国产精品扒开做爽爽爽的视频 | 91久久精 | 综合激情亚洲 | wwwww在线观看 | 欧美精品自拍偷拍 | 五月天六月色 | 日本少妇xxxxxx| 97自拍网| caopor超碰| 香蕉视频免费看 | 91手机视频 | 欧美成人dvd在线视频 | 99视频在线精品免费观看2 | 国产美女激情视频 | 亚洲卡一卡二卡三 | 一级黄色aa | 成人网站免费观看 | 国产小视频在线看 | 亚洲精品成人无码 | 国产日韩大片 | 国产精品白嫩极品美女 | 欧美高清另类 | 我和单位漂亮少妇激情 | 亚州av免费 | 蜜桃av在线| 亚洲综合影视 | 成年人小视频在线观看 | 国产又粗又猛又爽又黄无遮挡 | 爱爱视频欧美 | 久久噜噜色综合一区二区 | www.777色| 91丨porny丨| 日韩午夜在线播放 | 男女日日| 九九色在线 | 国产91福利 | 欧美乱大交xxxxx潮喷l头像 | 91国产精品| 黄色片网站免费在线观看 | 日本不卡视频 | 国产freexxxx性播放麻豆 | 就操网| 欧美jjzz| 精品福利在线 | 日本道中文字幕 | 成人深夜福利视频 | 日本午夜一区 | 爱操综合| 久久精品国产一区 | 天天撸天天操 | 麻豆观看 | 国产suv精品一区二区 | 欧美日韩国产综合网 | 日韩精品在线观看一区二区三区 | 国产在线成人精品午夜 | 一本高清dvd在线播放 | 亚洲xx视频 | 一起操17c | 欧美黄色大片免费观看 | av免费在线观 | 国产亚洲无 | 男人天堂亚洲天堂 | 婷婷丁香激情五月 | 国产小视频在线 | 美女扒开尿口让男人捅爽 | 欧美日韩国产二区 | 国产极品999 | 丁香啪啪综合成人亚洲 | 另类二区| 国产精品国产三级国产播12软件 | 亚洲天堂色 | 国产高清自拍视频 | 五月婷婷俺也去 | 亚洲中文字幕在线观看 | 久久亚洲av无码精品色午夜麻豆 | www.成人av.com | 国产伦精品一区二区三区视频网站 | 国产天堂在线观看 | 久久精品无码毛片 | av免播放器 | 国产男男一区二区三区 | 国产后入清纯学生妹 |