關于springboot啟動配置加載的那點事兒

前言

現(xiàn)在幾乎所有的java開發(fā)都會用到springboot哲身,除了很老很老的項目做修,應該不會再有人直接用jsp脚猾,servlet等寫web項目了吧葱峡,直接用spring的都很少見了。
今天發(fā)生的這個問題就得從springboot說起龙助。我們都知道springboot遵循約定大于配置的規(guī)則砰奕,盡量將spring中的配置減少,幾行代碼就可以跑一個web項目,但是默認的東西越多军援,其實隱藏的東西也就越多常空,一旦碰到什么問題,如果沒點準備盖溺,真的是會手忙腳亂的漓糙。

問題描述

說起來也不復雜,新拆分了一個項目烘嘱,公司用的apollo作為配置中心昆禽,所以要做一些基本配置,讓新項目從apollo拉取配置蝇庭。本以為簡單的Ctrl+C醉鳖,Ctrl+V搞定,結果啟動的時候報dubbo配置找不到哮内,反復查看apollo盗棵,一個字母一個字母的比對過去,確定配置沒有配錯的北发,但是怎么就找不到呢纹因?

源碼分析

一般這種問題想從網(wǎng)上找到答案的可能性微乎其微,只好自己動手琳拨,深入源碼瞭恰,看看到底是哪個妖怪在作祟。

SpringApplicationRunListener和ApplicationContextInitializer

Dubbo配置的加載是架構組jar包提供的狱庇,定義了一個SpringApplicationRunListener的實現(xiàn)類惊畏,而apollo的配置加載是在ApplicationContextInitializer的一個實現(xiàn)類ApolloApplicationContextInitializer中處理的。所以一開始的懷疑Listener和Initializer在應用啟動的時候的順序問題密任。
因為DubboListener里面加載dubbo的配置的代碼在SpringApplicationRunListener的contextLoaded方法中颜启,多以可以從下面SpringApplication的源碼看到,Initializer的initialize方法是在Listener的contextLoaded方法之前執(zhí)行的

private void prepareContext(ConfigurableApplicationContext context,
            ConfigurableEnvironment environment, SpringApplicationRunListeners listeners,
            ApplicationArguments applicationArguments, Banner printedBanner) {
    context.setEnvironment(environment);
    postProcessApplicationContext(context);
    // Initializer的initialize方法在這里執(zhí)行
    applyInitializers(context);
    listeners.contextPrepared(context);
    if (this.logStartupInfo) {
        logStartupInfo(context.getParent() == null);
        logStartupProfileInfo(context);
    }

    // Add boot specific singleton beans
    context.getBeanFactory().registerSingleton("springApplicationArguments",
            applicationArguments);
    if (printedBanner != null) {
        context.getBeanFactory().registerSingleton("springBootBanner", printedBanner);
    }

    // Load the sources
    Set<Object> sources = getAllSources();
    Assert.notEmpty(sources, "Sources must not be empty");
    load(context, sources.toArray(new Object[0]));
    // Listener的contextLoaded方法在這里執(zhí)行
    listeners.contextLoaded(context);
}

debug源碼

猜測不對浪讳,只好跟著啟動的源碼debug觀察了缰盏。這里省略一開始的猜測和嘗試,直接進入重點:調試的時候有個發(fā)現(xiàn)驻债,apollo的是否啟用的配置值居然是false爷光!可以從代碼看到譬涡,方法直接返回了,并沒有去加載apollo中的配置值漩勤,所以并不是順序有問題笙以,而是一開始是否啟用的配置值有問題淌实。

public void initialize(ConfigurableApplicationContext context) {
    ConfigurableEnvironment environment = context.getEnvironment();

    initializeSystemProperty(environment);
    // 如果這里配置是false,那方法直接return了
    String enabled = environment.getProperty(PropertySourcesConstants.APOLLO_BOOTSTRAP_ENABLED, "false");
    if (!Boolean.valueOf(enabled)) {
      logger.debug("Apollo bootstrap config is not enabled for context {}, see property: ${{}}", context, PropertySourcesConstants.APOLLO_BOOTSTRAP_ENABLED);
      return;
    }
    // 省略

查看項目中的application.properties文件,沒啥問題啊(本來就是其他項目拷過來的拆祈,能有啥問題)恨闪,那怎么就讀成false了呢?

apollo.bootstrap.enabled=true
apollo.bootstrap.namespaces=application,dev.common

只好繼續(xù)debug讓人頭大的源碼放坏,還是略過那些不重要的代碼咙咽,直接來看重點和結論:

  1. 第一次進入SimpleApplicationEventMulticaster的這個方法,這個時候其實是應用啟動事件淤年,發(fā)現(xiàn)有4個監(jiān)聽器钧敞,但看上去沒一個像跟配置有關的


  2. 第二次進這個方法,這個時候事件類型是環(huán)境準備事件麸粮,其中有個監(jiān)聽器是ConfigFileApplicationListener


  3. 進入ConfigFileApplicationListener的事件處理方法


  4. 通過ConfigFileApplicationListener的方法調用鏈onApplicationEnvironmentPreparedEvent --> postProcessEnvironment --> addPropertySources直接進入到內(nèi)部類Loader的下面這個方法溉苛,其中常量NO_SEARCH_NAMES是包含單個null元素的集合,這里獲取到的names就是配置文件的名稱弄诲。
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));
    });
}
  1. 小心翼翼的一步一步往下走愚战,本以為不會走進if條件,這樣讀到的就是application配置文件了齐遵,結果居然走了進去寂玲,而且"spring.config.name"對應的value是boostrap,而項目里根本沒有配置boostrap.yaml文件梗摇,那這個值是哪來的呢敢茁?


  2. 找了個能正常啟動的項目,同樣的地方打上了斷點留美,發(fā)現(xiàn)沒進if條件彰檬,"spring.config.name"這個配置到底什么時候設置進去的,反復debug了好幾遍谎砾,發(fā)現(xiàn)出錯的應用多了一個監(jiān)聽器BootstrapApplicationListener逢倍,而這個監(jiān)聽器的優(yōu)先級如下,比ConfigFileApplicationListener小多了(越小優(yōu)先級越高)
public static final int DEFAULT_ORDER = Ordered.HIGHEST_PRECEDENCE + 5;

  1. 現(xiàn)在就剩一個問題了景图,為啥會多這么一個監(jiān)聽器呢较雕?這個類所在的jar包是spring-cloud-context,分析了依賴發(fā)現(xiàn)正常啟動的應用果然是沒有這個依賴的挚币。

結論

有時候默認的約定會給開發(fā)人員帶來一定的困擾亮蒋,就像springcloud默認會去讀bootstrap的配置一樣,而差別僅僅是依賴中是否含有對應的jar包妆毕。本篇的問題其實還有一種解決方案慎玖,就是直接將application.properties里的配置移動到bootstrap.properties里,這樣apollo啟用的配置就能從bootstrap.properties里讀到了笛粘。

?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末趁怔,一起剝皮案震驚了整個濱河市湿硝,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌润努,老刑警劉巖关斜,帶你破解...
    沈念sama閱讀 206,214評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異铺浇,居然都是意外死亡痢畜,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,307評論 2 382
  • 文/潘曉璐 我一進店門鳍侣,熙熙樓的掌柜王于貴愁眉苦臉地迎上來丁稀,“玉大人,你說我怎么就攤上這事拱她《郏” “怎么了?”我有些...
    開封第一講書人閱讀 152,543評論 0 341
  • 文/不壞的土叔 我叫張陵秉沼,是天一觀的道長桶雀。 經(jīng)常有香客問我,道長唬复,這世上最難降的妖魔是什么矗积? 我笑而不...
    開封第一講書人閱讀 55,221評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮敞咧,結果婚禮上棘捣,老公的妹妹穿的比我還像新娘。我一直安慰自己休建,他們只是感情好乍恐,可當我...
    茶點故事閱讀 64,224評論 5 371
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著测砂,像睡著了一般茵烈。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上砌些,一...
    開封第一講書人閱讀 49,007評論 1 284
  • 那天呜投,我揣著相機與錄音,去河邊找鬼存璃。 笑死仑荐,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的纵东。 我是一名探鬼主播粘招,決...
    沈念sama閱讀 38,313評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼篮迎!你這毒婦竟也來了男图?” 一聲冷哼從身側響起示姿,我...
    開封第一講書人閱讀 36,956評論 0 259
  • 序言:老撾萬榮一對情侶失蹤甜橱,失蹤者是張志新(化名)和其女友劉穎逊笆,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體岂傲,經(jīng)...
    沈念sama閱讀 43,441評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡难裆,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,925評論 2 323
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了镊掖。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片乃戈。...
    茶點故事閱讀 38,018評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖亩进,靈堂內(nèi)的尸體忽然破棺而出症虑,到底是詐尸還是另有隱情,我是刑警寧澤归薛,帶...
    沈念sama閱讀 33,685評論 4 322
  • 正文 年R本政府宣布谍憔,位于F島的核電站,受9級特大地震影響主籍,放射性物質發(fā)生泄漏习贫。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,234評論 3 307
  • 文/蒙蒙 一千元、第九天 我趴在偏房一處隱蔽的房頂上張望苫昌。 院中可真熱鬧,春花似錦幸海、人聲如沸祟身。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,240評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽袜硫。三九已至,卻和暖如春议纯,著一層夾襖步出監(jiān)牢的瞬間父款,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,464評論 1 261
  • 我被黑心中介騙來泰國打工瞻凤, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留憨攒,地道東北人。 一個月前我還...
    沈念sama閱讀 45,467評論 2 352
  • 正文 我出身青樓阀参,卻偏偏與公主長得像肝集,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子蛛壳,可洞房花燭夜當晚...
    茶點故事閱讀 42,762評論 2 345

推薦閱讀更多精彩內(nèi)容