springboot源碼走讀之二----命令行參數(shù)封裝與上下文環(huán)境準(zhǔn)備

前言

本文主要是接上文源碼走讀之一

  try {
            ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
            ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);
            configureIgnoreBeanInfo(environment);
            Banner printedBanner = printBanner(environment);
            context = createApplicationContext();
            exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class,
                    new Class[] { ConfigurableApplicationContext.class }, context);
            prepareContext(context, environment, listeners, applicationArguments, printedBanner);
            refreshContext(context);
            afterRefresh(context, applicationArguments);
            stopWatch.stop();
            if (this.logStartupInfo) {
                new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch);
            }
            listeners.started(context);
            callRunners(context, applicationArguments);
        }
        catch (Throwable ex) {
            handleRunFailure(context, ex, exceptionReporters, listeners);
            throw new IllegalStateException(ex);
        }

這段代碼而來。主要走讀

ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);

這兩步代碼婿禽。
首先來看第一步盖矫,參數(shù)封裝。

ApplicationArguments生成

ApplicationArguments的主要處理邏輯在于SimpleCommandLineArgsParserparse方法岗仑。方法實現(xiàn)如下:

public CommandLineArgs parse(String... args) {
        CommandLineArgs commandLineArgs = new CommandLineArgs();
        for (String arg : args) {
            if (arg.startsWith("--")) {
                String optionText = arg.substring(2, arg.length());
                String optionName;
                String optionValue = null;
                if (optionText.contains("=")) {
                    optionName = optionText.substring(0, optionText.indexOf('='));
                    optionValue = optionText.substring(optionText.indexOf('=')+1, optionText.length());
                }
                else {
                    optionName = optionText;
                }
                if (optionName.isEmpty() || (optionValue != null && optionValue.isEmpty())) {
                    throw new IllegalArgumentException("Invalid argument syntax: " + arg);
                }
                commandLineArgs.addOptionArg(optionName, optionValue);
            }
            else {
                commandLineArgs.addNonOptionArg(arg);
            }
        }
        return commandLineArgs;
    }

這里springboot命令行參數(shù)包括兩種,一種是以--開頭的參數(shù)聚请,類似key/value形式的荠雕。如--profile,--log.level等。一種是直接以value形式的驶赏,如foo等炸卑。具體參數(shù)的意義,跟業(yè)務(wù)相關(guān)煤傍。

最后這個commandLineArgs被放到什么地方了呢盖文?看如下代碼:

public DefaultApplicationArguments(String... args) {
        Assert.notNull(args, "Args must not be null");
        this.source = new Source(args);
        this.args = args;
    }

我們進(jìn)一步進(jìn)入Source中,找到如下代碼:

public PropertySource(String name, T source) {
        Assert.hasText(name, "Property source name must contain at least one character");
        Assert.notNull(source, "Property source must not be null");
        this.name = name;
        this.source = source;
    }

這里初始化一個PropertySource蚯姆,name為:commandLineArgs五续,value就為上面初始化的CommandLineArgs
這里龄恋,只要業(yè)務(wù)能獲取到applicationArguments疙驾,就能獲取到我們從命令行中傳入的參數(shù)。
通常篙挽,我們會通過environment來獲取參數(shù)荆萤。例子如下:

 ApplicationContext ctx = SpringApplication.run(StudyApplication.class);
 System.out.println(ctx.getEnvironment().getProperty("foo"));

這里就會在控制臺中打印出key為“foo”的值。那么铣卡,environment是如何構(gòu)造的呢链韭?這就到了接下來要看的代碼中了,即environment的構(gòu)造煮落。

Environment的構(gòu)造

Environment的主要代碼如下:

private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners,
            ApplicationArguments applicationArguments) {
        // Create and configure the environment
        // 創(chuàng)建一個environment對象敞峭。如果是`SERVLET`,則new一個StandardServletEnvironment,如果是`REACTIVE`,則new一個StandardReactiveWebEnvironment蝉仇,否則初始化一個StandardEnvironment旋讹。初始化對象的時候殖蚕,創(chuàng)建一些java標(biāo)準(zhǔn)的環(huán)境參數(shù),如`systemEnvironment`和`systemProperties`及對應(yīng)容器特有的環(huán)境參數(shù)沉迹,如`servletConfigInitParams`和`servletContextInitParams`
        ConfigurableEnvironment environment = getOrCreateEnvironment();
//該步驟為設(shè)置一些默認(rèn)的converter和formatter及設(shè)置命令行參數(shù)到environment中睦疫,還有設(shè)置應(yīng)用程序中設(shè)置的profile及active profile。
        configureEnvironment(environment, applicationArguments.getSourceArgs());
//配置configurationProperties的值
        ConfigurationPropertySources.attach(environment);
//觸發(fā)環(huán)境準(zhǔn)備完成事件鞭呕,事件的消費者在springboot的代碼中蛤育,有如下地方:
// FileEncodingApplicationListener,AnsiOutputApplicationListener,ConfigFileApplicationListener【重要,加載配置文件的地方葫松,下面會專門講】瓦糕,LoggingApplicationListener 日志系統(tǒng),WebEnvironmentPropertySourceInitializer
        listeners.environmentPrepared(environment);
//綁定環(huán)境到springapplication上腋么。spring.main配置【具體作用咕娄,以后用到的時候在做說明】
        bindToSpringApplication(environment);
              //如果不是自定義環(huán)境,則轉(zhuǎn)換之珊擂。
        if (!this.isCustomEnvironment) {
            environment = new EnvironmentConverter(getClassLoader()).convertEnvironmentIfNecessary(environment,
                    deduceEnvironmentClass());
        }
        ConfigurationPropertySources.attach(environment);
        return environment;
    }

到此圣勒,環(huán)境準(zhǔn)備完成。
總結(jié)代碼未玻,環(huán)境準(zhǔn)備主要做了如下幾件事情:
1.確定active環(huán)境灾而。
2.確定環(huán)境參數(shù),jvm參數(shù)及os參數(shù)扳剿。
3.加載properties,yml配置文件昼激。
4.確定spring.main配置庇绽。

configureIgnoreBeanInfo

這里設(shè)置spring.beaninfo.ignore的值,若沒有指定橙困,則設(shè)置為true瞧掺。具體用處,有待進(jìn)一步走讀代碼

printBanner

這一步是打印banner圖凡傅,即


springboot banner圖

接下來辟狈,真正進(jìn)入springboot的重點部分了,跟spring真正結(jié)合的地方來了夏跷。
即如下代碼

//創(chuàng)建spring context
context = createApplicationContext();
prepareContext(context, environment, listeners, applicationArguments, printedBanner);
//【重點中的重點】調(diào)用spring的refresh方法哼转,進(jìn)行spring的bean的加載。
refreshContext(context);

下一篇我們將詳細(xì)介紹spring的context的初始化槽华。這里需要對spring的源碼及原理有一些了解壹蔓。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市猫态,隨后出現(xiàn)的幾起案子佣蓉,更是在濱河造成了極大的恐慌披摄,老刑警劉巖,帶你破解...
    沈念sama閱讀 212,816評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件勇凭,死亡現(xiàn)場離奇詭異疚膊,居然都是意外死亡,警方通過查閱死者的電腦和手機虾标,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,729評論 3 385
  • 文/潘曉璐 我一進(jìn)店門酿联,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人夺巩,你說我怎么就攤上這事贞让。” “怎么了柳譬?”我有些...
    開封第一講書人閱讀 158,300評論 0 348
  • 文/不壞的土叔 我叫張陵喳张,是天一觀的道長。 經(jīng)常有香客問我美澳,道長销部,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,780評論 1 285
  • 正文 為了忘掉前任制跟,我火速辦了婚禮,結(jié)果婚禮上雨膨,老公的妹妹穿的比我還像新娘擂涛。我一直安慰自己聊记,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 65,890評論 6 385
  • 文/花漫 我一把揭開白布排监。 她就那樣靜靜地躺著,像睡著了一般舆床。 火紅的嫁衣襯著肌膚如雪棋蚌。 梳的紋絲不亂的頭發(fā)上挨队,一...
    開封第一講書人閱讀 50,084評論 1 291
  • 那天,我揣著相機與錄音瞒瘸,去河邊找鬼。 笑死情臭,一個胖子當(dāng)著我的面吹牛省撑,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播竟秫,決...
    沈念sama閱讀 39,151評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼娃惯,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了肥败?” 一聲冷哼從身側(cè)響起趾浅,我...
    開封第一講書人閱讀 37,912評論 0 268
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎馒稍,沒想到半個月后皿哨,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,355評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡纽谒,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,666評論 2 327
  • 正文 我和宋清朗相戀三年证膨,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片鼓黔。...
    茶點故事閱讀 38,809評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡央勒,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出澳化,到底是詐尸還是另有隱情崔步,我是刑警寧澤,帶...
    沈念sama閱讀 34,504評論 4 334
  • 正文 年R本政府宣布缎谷,位于F島的核電站井濒,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏慎陵。R本人自食惡果不足惜眼虱,卻給世界環(huán)境...
    茶點故事閱讀 40,150評論 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望席纽。 院中可真熱鬧,春花似錦撞蚕、人聲如沸润梯。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,882評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽纺铭。三九已至,卻和暖如春刀疙,著一層夾襖步出監(jiān)牢的瞬間舶赔,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,121評論 1 267
  • 我被黑心中介騙來泰國打工谦秧, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留竟纳,地道東北人撵溃。 一個月前我還...
    沈念sama閱讀 46,628評論 2 362
  • 正文 我出身青樓,卻偏偏與公主長得像锥累,于是被迫代替她去往敵國和親缘挑。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,724評論 2 351

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