溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

Java?SpringBoot核心源碼的示例分析

發(fā)布時(shí)間:2021-12-29 10:21:18 來源:億速云 閱讀:115 作者:柒染 欄目:開發(fā)技術(shù)

本篇文章給大家分享的是有關(guān)Java SpringBoot核心源碼的示例分析,小編覺得挺實(shí)用的,因此分享給大家學(xué)習(xí),希望大家閱讀完這篇文章后可以有所收獲,話不多說,跟著小編一起來看看吧。

    SpringBoot源碼主線分析

    我們要分析一個(gè)框架的源碼不可能通過一篇文章就搞定的,本文我們就來分析下SpringBoot源碼中的主線流程。先掌握SpringBoot項(xiàng)目啟動(dòng)的核心操作,然后我們?cè)偕钊朊恳粋€(gè)具體的實(shí)現(xiàn)細(xì)節(jié),注:本系列源碼都以SpringBoot2.2.5.RELEASE版本來講解

    1.SpringBoot啟動(dòng)的入口

    當(dāng)我們啟動(dòng)一個(gè)SpringBoot項(xiàng)目的時(shí)候,入口程序就是main方法,而在main方法中就執(zhí)行了一個(gè)run方法。

    @SpringBootApplication
    public class StartApp {
    	public static void main(String[] args) {
    		SpringApplication.run(StartApp.class);
    	}
    }

    2.run方法

    然后我們進(jìn)入run()方法中看。代碼比較簡(jiǎn)單

    	public static ConfigurableApplicationContext run(Class<?> primarySource, String... args) {
    		// 調(diào)用重載的run方法,將傳遞的Class對(duì)象封裝為了一個(gè)數(shù)組
    		return run(new Class<?>[] { primarySource }, args);
    	}

    調(diào)用了重載的一個(gè)run()方法,將我們傳遞進(jìn)來的類對(duì)象封裝為了一個(gè)數(shù)組,僅此而已。我們?cè)龠M(jìn)入run()方法。

    	public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {
    		// 創(chuàng)建了一個(gè)SpringApplication對(duì)象,并調(diào)用其run方法
    		// 1.先看下構(gòu)造方法中的邏輯
    		// 2.然后再看run方法的邏輯
    		return new SpringApplication(primarySources).run(args);
    	}

    在該方法中創(chuàng)建了一個(gè)SpringApplication對(duì)象。同時(shí)調(diào)用了SpringApplication對(duì)象的run方法。這里的邏輯有分支,先看下SpringApplication的構(gòu)造方法中的邏輯

    3.SpringApplication構(gòu)造器

    我們進(jìn)入SpringApplication的構(gòu)造方法,看的核心代碼為

    	public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
    		// 傳遞的resourceLoader為null
    		this.resourceLoader = resourceLoader;
    		Assert.notNull(primarySources, "PrimarySources must not be null");
    		// 記錄主方法的配置類名稱
    		this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
    		// 記錄當(dāng)前項(xiàng)目的類型
    		this.webApplicationType = WebApplicationType.deduceFromClasspath();
    		// 加載配置在spring.factories文件中的ApplicationContextInitializer對(duì)應(yīng)的類型并實(shí)例化
    		// 并將加載的數(shù)據(jù)存儲(chǔ)在了 initializers 成員變量中。
    		setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
    		// 初始化監(jiān)聽器 并將加載的監(jiān)聽器實(shí)例對(duì)象存儲(chǔ)在了listeners成員變量中
    		setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
    		// 反推main方法所在的Class對(duì)象 并記錄在了mainApplicationClass對(duì)象中
    		this.mainApplicationClass = deduceMainApplicationClass();
    	}

    在本方法中完成了幾個(gè)核心操作

    1.推斷當(dāng)前項(xiàng)目的類型

    2.加載配置在spring.factories文件中的ApplicationContextInitializer中的類型并實(shí)例化后存儲(chǔ)在了initializers中。

    3.和2的步驟差不多,完成監(jiān)聽器的初始化操作,并將實(shí)例化的監(jiān)聽器對(duì)象存儲(chǔ)在了listeners成員變量中

    4.通過StackTrace反推main方法所在的Class對(duì)象

    上面的核心操作具體的實(shí)現(xiàn)細(xì)節(jié)我們?cè)诤竺娴脑敿?xì)文章會(huì)給大家剖析

    4.run方法

    接下來我們?cè)诨氐絊pringApplication.run()方法中。

    	public ConfigurableApplicationContext run(String... args) {
    		// 創(chuàng)建一個(gè)任務(wù)執(zhí)行觀察器
    		StopWatch stopWatch = new StopWatch();
    		// 開始執(zhí)行記錄執(zhí)行時(shí)間
    		stopWatch.start();
    		// 聲明 ConfigurableApplicationContext 對(duì)象
    		ConfigurableApplicationContext context = null;
    		// 聲明集合容器用來存儲(chǔ) SpringBootExceptionReporter 啟動(dòng)錯(cuò)誤的回調(diào)接口
    		Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
    		// 設(shè)置了一個(gè)名為java.awt.headless的系統(tǒng)屬性
    		// 其實(shí)是想設(shè)置該應(yīng)用程序,即使沒有檢測(cè)到顯示器,也允許其啟動(dòng).
    		//對(duì)于服務(wù)器來說,是不需要顯示器的,所以要這樣設(shè)置.
    		configureHeadlessProperty();
    		// 獲取 SpringApplicationRunListener 加載的是 EventPublishingRunListener
    		// 獲取啟動(dòng)時(shí)到監(jiān)聽器
    		SpringApplicationRunListeners listeners = getRunListeners(args);
    		// 觸發(fā)啟動(dòng)事件
    		listeners.starting();
    		try {
    			// 構(gòu)造一個(gè)應(yīng)用程序的參數(shù)持有類
    			ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
    			// 創(chuàng)建并配置環(huán)境
    			ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);
    			// 配置需要忽略的BeanInfo信息
    			configureIgnoreBeanInfo(environment);
    			// 輸出的Banner信息
    			Banner printedBanner = printBanner(environment);
    			// 創(chuàng)建應(yīng)用上下文對(duì)象
    			context = createApplicationContext();
    			// 加載配置的啟動(dòng)異常處理器
    			exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class,
    					new Class[] { ConfigurableApplicationContext.class }, context);
    			// 刷新前操作
    			prepareContext(context, environment, listeners, applicationArguments, printedBanner);
    			// 刷新應(yīng)用上下文 完成Spring容器的初始化
    			refreshContext(context);
    			// 刷新后操作
    			afterRefresh(context, applicationArguments);
    			// 結(jié)束記錄啟動(dòng)時(shí)間
    			stopWatch.stop();
    			if (this.logStartupInfo) {
    				new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch);
    			}
    			// 事件廣播 啟動(dòng)完成了
    			listeners.started(context);
    			callRunners(context, applicationArguments);
    		}
    		catch (Throwable ex) {
    			// 事件廣播啟動(dòng)出錯(cuò)了
    			handleRunFailure(context, ex, exceptionReporters, listeners);
    			throw new IllegalStateException(ex);
    		}
    		try {
    			// 監(jiān)聽器運(yùn)行中
    			listeners.running(context);
    		}
    		catch (Throwable ex) {
    			handleRunFailure(context, ex, exceptionReporters, null);
    			throw new IllegalStateException(ex);
    		}
    		// 返回上下文對(duì)象--> Spring容器對(duì)象
    		return context;
    	}

    在這個(gè)方法中完成了SpringBoot項(xiàng)目啟動(dòng)的很多核心的操作,我們來總結(jié)下上面的步驟

    • 創(chuàng)建了一個(gè)任務(wù)執(zhí)行的觀察器,統(tǒng)計(jì)啟動(dòng)的時(shí)間

    • 聲明ConfigurableApplicationContext對(duì)象

    • 聲明集合容器來存儲(chǔ)SpringBootExceptionReporter即啟動(dòng)錯(cuò)誤的回調(diào)接口

    • 設(shè)置java.awt.headless的系統(tǒng)屬性

    • 獲取我們之間初始化的監(jiān)聽器(EventPublishingRunListener),并觸發(fā)starting事件

    • 創(chuàng)建ApplicationArguments這是一個(gè)應(yīng)用程序的參數(shù)持有類

    • 創(chuàng)建ConfigurableEnvironment這時(shí)一個(gè)配置環(huán)境的對(duì)象

    • 配置需要忽略的BeanInfo信息

    • 配置Banner信息對(duì)象

    • 創(chuàng)建對(duì)象的上下文對(duì)象

    • 加載配置的啟動(dòng)異常的回調(diào)異常處理器

    • 刷新應(yīng)用上下文,本質(zhì)就是完成Spring容器的初始化操作

    • 啟動(dòng)結(jié)束記錄啟動(dòng)耗時(shí)

    • 完成對(duì)應(yīng)的事件廣播

    • 返回應(yīng)用上下文對(duì)象。

    以上就是Java SpringBoot核心源碼的示例分析,小編相信有部分知識(shí)點(diǎn)可能是我們?nèi)粘9ぷ鲿?huì)見到或用到的。希望你能通過這篇文章學(xué)到更多知識(shí)。更多詳情敬請(qǐng)關(guān)注億速云行業(yè)資訊頻道。

    向AI問一下細(xì)節(jié)

    免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

    AI