国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

【框架源碼】SpringBoot核心源碼解讀之啟動類源碼分析

這篇具有很好參考價值的文章主要介紹了【框架源碼】SpringBoot核心源碼解讀之啟動類源碼分析。希望對大家有所幫助。如果存在錯誤或未考慮完全的地方,請大家不吝賜教,您也可以點擊"舉報違法"按鈕提交疑問。

【框架源碼】SpringBoot核心源碼解讀之啟動類源碼分析

首先我們要先帶著我們的疑問,spring boot是如何啟動應(yīng)用程序?去分析SpringBoot的啟動源碼。

我們在新建SpringBoot項目時,核心方法就是主類的run方法。

SpringApplication.run(ArchWebApplication.class, args)

【框架源碼】SpringBoot核心源碼解讀之啟動類源碼分析

我們點擊run方法進入到源碼中,這塊傳入的了一個我們當(dāng)前程序主類的類對象以及主程序參數(shù)。

	public static ConfigurableApplicationContext run(Class<?> primarySource,
			String... args) {
		return run(new Class<?>[] { primarySource }, args);
	}

再往下走,調(diào)用本身的run方法,這里就開始初始化SpringApplication對象啦,然后在調(diào)用run方法。初始化SpringApplication對象時也是將主類的類對象傳入進去,然后調(diào)用run方法,將主程序傳進來的參數(shù)傳進去。

	public static ConfigurableApplicationContext run(Class<?>[] primarySources,
			String[] args) {
		return new SpringApplication(primarySources).run(args);
	}

我們先來看SpringApplication對象初始化時都做了哪些操作。

同樣調(diào)用自身的雙參構(gòu)造方法,null為傳入的資源加載器。

	public SpringApplication(Class<?>... primarySources) {
		this(null, primarySources);
	}

再往下走就到了初始化SpringApplication的核心邏輯啦。

	public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
    //首先是將傳來的資源加載器進行賦值,當(dāng)然我們知道這個資源加載器是null
		this.resourceLoader = resourceLoader;
    //然后在進行類對象的判空
		Assert.notNull(primarySources, "PrimarySources must not be null");
    //然后將傳進來的類對像的數(shù)組轉(zhuǎn)成list在轉(zhuǎn)成set。
    //(我估計這里是為了去重類對象,因為可以穿進來的可變參數(shù)有重復(fù)的,可變參數(shù)實質(zhì)就是一個數(shù)組)。
		this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
    //deduceFromClasspath 方法的目的是用來判斷應(yīng)用是servlet還是reactive應(yīng)用
		this.webApplicationType = WebApplicationType.deduceFromClasspath();
    //這一步的邏輯是從spring.factories文件中讀取 key為ApplicationContextInitializer的類信息,采用反射實例化對象
    //設(shè)置上下文信息
		setInitializers((Collection) getSpringFactoriesInstances(
				ApplicationContextInitializer.class));
    //這一步的邏輯同上,也是從spring.factories文件中讀取 key為ApplicationListener的類信息,采用反射實例化對象
  	//設(shè)置監(jiān)聽器
		setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
    //判斷是否為main函數(shù),配置主函數(shù)啟動類 class信息
		this.mainApplicationClass = deduceMainApplicationClass();
	}

上面是一個創(chuàng)建SpringApplication的整體邏輯,那么我們在具體看一下 WebApplicationType.deduceFromClasspath()里面的邏輯是怎么樣的。WebApplicationType本身是一個枚舉類。

  //一共三種方式返回服務(wù)條件的一種	
	static WebApplicationType deduceFromClasspath() {
    //判斷當(dāng)前應(yīng)用是不是 REACTIVE應(yīng)用
		if (ClassUtils.isPresent(WEBFLUX_INDICATOR_CLASS, null)
				&& !ClassUtils.isPresent(WEBMVC_INDICATOR_CLASS, null)
				&& !ClassUtils.isPresent(JERSEY_INDICATOR_CLASS, null)) {
			return WebApplicationType.REACTIVE;
		}
    //判斷是不是 非web應(yīng)用
		for (String className : SERVLET_INDICATOR_CLASSES) {
			if (!ClassUtils.isPresent(className, null)) {
				return WebApplicationType.NONE;
			}
		}
    //都不是的話返回 web應(yīng)用方式
		return WebApplicationType.SERVLET;
	}

ClassUtils.isPresent()這個方法的主要作用是通過反射判斷相應(yīng)的類存不存在。

	public static boolean isPresent(String className, @Nullable ClassLoader classLoader) {
		try {
			forName(className, classLoader);
			return true;
		}
		catch (IllegalAccessError err) {
			throw new IllegalStateException("Readability mismatch in inheritance hierarchy of class [" +
					className + "]: " + err.getMessage(), err);
		}
		catch (Throwable ex) {
			// Typically ClassNotFoundException or NoClassDefFoundError...
			return false;
		}
	}

ok,分析完WebApplicationType.deduceFromClasspath(),我們在來看一下getSpringFactoriesInstances()這個方法的核心邏輯。

	private <T> Collection<T> getSpringFactoriesInstances(Class<T> type,
			Class<?>[] parameterTypes, Object... args) {
    //獲取ClassLoader
		ClassLoader classLoader = getClassLoader();
		//這一步很重要,重點在于內(nèi)部是從spring.factories中獲取對應(yīng)的類信息
		Set<String> names = new LinkedHashSet<>(
				SpringFactoriesLoader.loadFactoryNames(type, classLoader));
    //等到需要加載的類信息之后,通過反射創(chuàng)建對象。
		List<T> instances = createSpringFactoriesInstances(type, parameterTypes,
				classLoader, args, names);
    //排序
		AnnotationAwareOrderComparator.sort(instances);
		return instances;
	}

我們來看一下,loadFactoryNames中都干了什么,它這里面的核心就在于加載配置文件,反射實例化對象

public static List<String> loadFactoryNames(Class<?> factoryClass, @Nullable ClassLoader classLoader) {
		String factoryClassName = factoryClass.getName();
		return loadSpringFactories(classLoader).getOrDefault(factoryClassName, Collections.emptyList());
	}

	//核心邏輯在這個方法
	private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) {
		//首先先去判斷下Map中是否有值,有值的話,就直接返回,相當(dāng)于一個本地緩存。
    MultiValueMap<String, String> result = cache.get(classLoader);
		if (result != null) {
			return result;
		}

		try {
      //如果Map沒有值的話,獲取資源目錄下的spring.factories文件。加載配置
      //源碼中 FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories"
			Enumeration<URL> urls = (classLoader != null ?
					classLoader.getResources(FACTORIES_RESOURCE_LOCATION) :
					ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION));
			result = new LinkedMultiValueMap<>();
      //下面就是遍歷放進map中
			while (urls.hasMoreElements()) {
				URL url = urls.nextElement();
				UrlResource resource = new UrlResource(url);
				Properties properties = PropertiesLoaderUtils.loadProperties(resource);
				for (Map.Entry<?, ?> entry : properties.entrySet()) {
					String factoryClassName = ((String) entry.getKey()).trim();
					for (String factoryName : StringUtils.commaDelimitedListToStringArray((String) entry.getValue())) {
						result.add(factoryClassName, factoryName.trim());
					}
				}
			}
			cache.put(classLoader, result);
			return result;
		}
		catch (IOException ex) {
			throw new IllegalArgumentException("Unable to load factories from location [" +
					FACTORIES_RESOURCE_LOCATION + "]", ex);
		}
	}

【框架源碼】SpringBoot核心源碼解讀之啟動類源碼分析
【框架源碼】SpringBoot核心源碼解讀之啟動類源碼分析

OK,這里關(guān)于SpringApplication初始化的操作就已經(jīng)完成啦,那么下面我們在一下run()方法里都做些什么操作。傳進去的是主程序的參數(shù)。

【框架源碼】SpringBoot核心源碼解讀之啟動類源碼分析

public ConfigurableApplicationContext run(String... args) {
  	//創(chuàng)建StopWatch對象,用于記錄服務(wù)啟動的時間
		StopWatch stopWatch = new StopWatch();
  	//記錄服務(wù)啟動開始時間
		stopWatch.start();
  	//定義應(yīng)用程序上下文
		ConfigurableApplicationContext context = null;
		Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
  	//配置運行程序的系統(tǒng)環(huán)境,以確保可正確的運行。
		configureHeadlessProperty();
  	//獲取在SpringApplication上的所有監(jiān)聽器。
		SpringApplicationRunListeners listeners = getRunListeners(args);
  	//通知所有監(jiān)聽器,啟動應(yīng)用程序
		listeners.starting();
		try {
      //封裝應(yīng)用程序的主程序參數(shù)
			ApplicationArguments applicationArguments = new DefaultApplicationArguments(
					args);
      //準(zhǔn)備應(yīng)用環(huán)境,生成環(huán)境變量
			ConfigurableEnvironment environment = prepareEnvironment(listeners,
					applicationArguments);
			configureIgnoreBeanInfo(environment);
      //打印應(yīng)用程序的banner
			Banner printedBanner = printBanner(environment);
      //創(chuàng)建應(yīng)用上下文對象
			context = createApplicationContext();
      //從spring.factories中獲取SpringBootExceptionReporter類型的異常解析器。
			exceptionReporters = getSpringFactoriesInstances(
					SpringBootExceptionReporter.class,
					new Class[] { ConfigurableApplicationContext.class }, context);
      //用已有的數(shù)據(jù)準(zhǔn)備上下文,為刷新做準(zhǔn)備
			prepareContext(context, environment, listeners, applicationArguments,
					printedBanner);
      //啟動應(yīng)用程序上下文,通過refresh實現(xiàn)
			refreshContext(context);
      //上下文刷新后執(zhí)行一些后置處理
			afterRefresh(context, applicationArguments);
      //記錄結(jié)束時間
			stopWatch.stop();
      //判斷是否需要記錄應(yīng)用程序的啟動信息
			if (this.logStartupInfo) {
				new StartupInfoLogger(this.mainApplicationClass)
						.logStarted(getApplicationLog(), stopWatch);
			}
      //通知所有監(jiān)聽器,應(yīng)用程序已經(jīng)啟動,傳遞上下文對象和啟動時間
			listeners.started(context);
      //運行所有已經(jīng)注冊的runner
			callRunners(context, applicationArguments);
		}
		catch (Throwable ex) {
			handleRunFailure(context, ex, exceptionReporters, listeners);
			throw new IllegalStateException(ex);
		}

		try {
      //發(fā)布應(yīng)用上下文就緒事件
			listeners.running(context);
		}
		catch (Throwable ex) {
			handleRunFailure(context, ex, exceptionReporters, null);
			throw new IllegalStateException(ex);
		}
		return context;
	}

【框架源碼】SpringBoot核心源碼解讀之啟動類源碼分析

ok,下面我們來斷點調(diào)試下springboot啟動類的源碼執(zhí)行。

啟動SpringBoot應(yīng)用程序。
【框架源碼】SpringBoot核心源碼解讀之啟動類源碼分析【框架源碼】SpringBoot核心源碼解讀之啟動類源碼分析【框架源碼】SpringBoot核心源碼解讀之啟動類源碼分析【框架源碼】SpringBoot核心源碼解讀之啟動類源碼分析
【框架源碼】SpringBoot核心源碼解讀之啟動類源碼分析

后面就是排序?qū)嵗?,返回實例。

【框架源碼】SpringBoot核心源碼解讀之啟動類源碼分析
【框架源碼】SpringBoot核心源碼解讀之啟動類源碼分析

剩下的就是我們上面畫的那些流程啦。

【框架源碼】SpringBoot核心源碼解讀之啟動類源碼分析【框架源碼】SpringBoot核心源碼解讀之啟動類源碼分析【框架源碼】SpringBoot核心源碼解讀之啟動類源碼分析
【框架源碼】SpringBoot核心源碼解讀之啟動類源碼分析

ok,至此SpringBoot啟動的全流程就已經(jīng)完成啦,最后在總結(jié)一下大體的流程。文章來源地址http://www.zghlxwxcb.cn/news/detail-463866.html

  • 初始化SpringApplication,運行SpringApplication的run方法
  • 讀取 spring.factories 的多個初始化器和監(jiān)聽器
  • 配置項目中環(huán)境變量、jvm配置信息、配置文件信息
  • 預(yù)初始化環(huán)境,創(chuàng)建環(huán)境對象
  • 創(chuàng)建Spring容器對象(ApplicationContext)
  • 調(diào)用spring的refresh加載IOC容器、自動配置類,并創(chuàng)建bean等信息
  • 調(diào)用很多監(jiān)聽器并傳遞上下文對象
  • 運行相關(guān)runner

到了這里,關(guān)于【框架源碼】SpringBoot核心源碼解讀之啟動類源碼分析的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實不符,請點擊違法舉報進行投訴反饋,一經(jīng)查實,立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費用

相關(guān)文章

  • SpringBoot的啟動流程源碼分析

    SpringBoot的啟動流程源碼分析

    new 一個IOC容器,傳入配置好的文件xml,在這個地方打bug 在這個debug的棧幀中,下面幾個不用看,直接看到getBean 內(nèi)容如圖所示,name傳的就是我們在xml的bean標(biāo)簽的id,這里是instanceA 進入到doGetBean后,因為我是從IOC初始化容器debug進來的所以第一次通過。 Object sharedInstance = getSingl

    2024年01月24日
    瀏覽(18)
  • SpringBoot源碼學(xué)習(xí)4——SpringBoot內(nèi)嵌Tomcat啟動流程源碼分析

    SpringBoot源碼學(xué)習(xí)4——SpringBoot內(nèi)嵌Tomcat啟動流程源碼分析

    系列文章目錄和關(guān)于我 我在初學(xué)spring的時候,很懵逼,因為整個項目中不存在main方法,讓我有點摸不著頭腦。那時候我知道有個東西叫tomcat是它監(jiān)聽了端口,解析了協(xié)議調(diào)到了我的servlet。 在我初學(xué)SpringBoot的時候,很懵逼,有main方法了,但是tomcat在哪里呢,又是如何啟動起

    2024年02月04日
    瀏覽(20)
  • SpringBoot3.X源碼分析(啟動流程)

    SpringBoot3.X源碼分析(啟動流程)

    1 啟動入口 靜態(tài)輔助類,可用于運行使用默認配置(即我們添加的一系列注解)的指定源的 SpringApplication 。 primarySource - 要載入的主要源,即指定源,這里為傳入的 Application.class ?Class? :泛型決定了任何類都可以傳入 args - 應(yīng)用程序參數(shù)(通常從main方法傳遞) 返回:正在運

    2024年01月23日
    瀏覽(20)
  • SpringBoot配置外部Tomcat項目啟動流程源碼分析

    SpringBoot配置外部Tomcat項目啟動流程源碼分析

    SpringBoot應(yīng)用默認以Jar包方式并且使用內(nèi)置Servlet容器(默認Tomcat),該種方式雖然簡單但是默認不支持JSP并且優(yōu)化容器比較復(fù)雜。故而我們可以使用習(xí)慣的外置Tomcat方式并將項目打War包。 ① 同樣使用Spring Initializer方式創(chuàng)建項目 ② 打包方式選擇\\\"war\\\" ③ 選擇添加的模塊 ④ 創(chuàng)建的

    2024年02月04日
    瀏覽(25)
  • SpringBoot源碼分析之Tomcat是如何在SpringBoot中啟動的?

    SpringBoot源碼分析之Tomcat是如何在SpringBoot中啟動的?

    一.前言 我們知道SpringBoot可以直接把傳統(tǒng)的war包打成可執(zhí)行的jar包,直接啟動。這得益于SpringBoot內(nèi)置了容器可以直接啟動。本文將以 Tomcat 為例,來看看 SpringBoot 是如何啟動 Tomcat 的。 一.SpringApplication初始化 調(diào)用到最終的run方法我們來看一下 這里面首先創(chuàng)建了一個SpringAppl

    2024年02月05日
    瀏覽(23)
  • SpringBoot-Run啟動流程(源碼分析)—看不懂來揍我

    SpringBoot-Run啟動流程(源碼分析)—看不懂來揍我

    目錄 前言 Run()方法 1、實例化SpringApplication對象 1、加載容器 2、裝配初始化器 3、裝配監(jiān)聽器 ?4、加載主類 2、執(zhí)行Run()方法 1、設(shè)置headless 2、啟用SpringApplicationListener 3、加載Banner 1、圖片Banner 2、文本Banner 4、異常報告類加載 5、準(zhǔn)備上下文???????? 6、刷新上下文 7、系統(tǒng)

    2024年02月14日
    瀏覽(23)
  • PaddleSeg分割框架解讀[01] 核心設(shè)計解析

    特別注意,這塊具體實現(xiàn)的類,如class Cityscapes(Dataset)等,稱為組件; 組件管理器,則為相應(yīng)的模型model管理器、數(shù)據(jù)集datasets管理器等。

    2024年02月20日
    瀏覽(22)
  • Springboot 核心注解和基本配置解讀

    Springboot 核心注解和基本配置解讀

    目錄 ? 1. Springboot 入門與原理 1.1 Springboot 簡介 1.1.1 什么是Springboot 1.1.2 Springboot 主要優(yōu)點 1.2 Springboot 相關(guān)注解 1.2.1 元注解 ?1.2.1.1 @Target 1.2.1.2 @Retention 1.2.2 @Configuration 1.2.3 @Import 1.2.3.1 直接注入 1.2.3.2?實現(xiàn) ImportSelector 注入 1.2.3.3?實現(xiàn) ImportBeanDefinitionRegistrar 接口 注入 1.2.4 @

    2024年02月09日
    瀏覽(49)
  • SpringSecurity源碼分析(一) SpringBoot集成SpringSecurity即Spring安全框架的加載過程

    SpringSecurity源碼分析(一) SpringBoot集成SpringSecurity即Spring安全框架的加載過程

    ? ? ? Spring Security是一個強大的并且高度可定制化的訪問控制框架。?它基于spring應(yīng)用。 Spring Security是聚焦于為java應(yīng)用提供授權(quán)和驗證的框架。像所有的spring項目一樣,Spring Security真正的強大在于可以非常簡單的拓展功能來實現(xiàn)自定義的需求。 ? ? ? 在分析SpringBoot集成的Sp

    2024年02月03日
    瀏覽(19)
  • CVPR 2023 | 主干網(wǎng)絡(luò)FasterNet 核心解讀 代碼分析

    本文分享來自CVPR 2023的論文,提出了一種 快速的主干網(wǎng)絡(luò),名為FasterNet 。 論文提出了 一種新的卷積算子,partial convolution,部分卷積(PConv) ,通過 減少冗余計算 和 內(nèi)存訪問 來更有效地提取空間特征。 創(chuàng)新在于部分卷積(PConv), 它選擇一部分通道的特性進行常規(guī)卷積 , 剩余

    2024年02月06日
    瀏覽(21)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包