日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

springboot启动过程_spring5/springboot2源码学习 -- spring boot 应用的启动过程

發布時間:2023/12/10 编程问答 33 豆豆
生活随笔 收集整理的這篇文章主要介紹了 springboot启动过程_spring5/springboot2源码学习 -- spring boot 应用的启动过程 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

推薦閱讀:

  • Spring全家桶筆記:Spring+Spring Boot+Spring Cloud+Spring MVC
  • 疫情期間“閉關修煉”,吃透這本Java核心知識,跳槽面試不心慌
  • 2020“閉關”跳槽季,啃透分布式三大技術:限流、緩存、通訊

基本環境

開發工具:Intellij IDEA 2017(盜)版

java版本:1.8.0_151

spring的github地址:spring-framework

準備:git clone或直接下載github上的spring源碼,導入idea中,在項目路徑下執行gradle build (如果本機沒有gradle環境,或者版本差很多,就用gradlew代替),會build很久,可以事先將阿里的maven倉庫地址加到repositories中,像這樣:

repositories { maven { url "http://maven.aliyun.com/nexus/content/groups/public/" } maven { url "https://repo.spring.io/plugins-release" }}

會用到的縮寫:

ApplicationContext -> ACApplicationContextInitializer -> ACIBeanFactory -> BFApplicationListener -> ALEnvironmentPostProcessor -> EPPspring boot 應用的啟動/*** @author pk* @date 2018/02/22*/@SpringBootApplicationpublic class SpringBootTwoStudyApplication {public static void main(String[] args) {SpringApplication springApplication = new SpringApplication(SpringBootTwoStudyApplication.class);//可以在run之前,對AC進行一些自定義的配置,添加點ApplicationListener,ApplicationContextInitializer啥的springApplication.run(args);}}

一.SpringApplication的初始化

代碼如下:

public SpringApplication(ResourceLoader resourceLoader, Class>... primarySources) { this.resourceLoader = resourceLoader; Assert.notNull(primarySources, "PrimarySources must not be null"); this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));//1 this.webApplicationType = deduceWebApplicationType();//2 setInitializers((Collection) getSpringFactoriesInstances( ApplicationContextInitializer.class));//3 setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));//4 this.mainApplicationClass = deduceMainApplicationClass();//5 }

1.設置啟動類primarySources到對應屬性

這個啟動類就是在初始化SpringApplication時候的參數,可以有多個

2.獲取web應用類型

  • 根據當前classpath下存在的類來判斷的:
  • 如果存在org.springframework.web.reactive.DispatcherHandler,就是REACTIVE
  • 如果不存在org.springframework.web.servlet.DispatcherServlet或者javax.servlet.Servlet,就是NONE
  • 否則,就是SERVLET

3.設置ApplicationContextInitializer

代碼如下:

private Collection getSpringFactoriesInstances(Class type, Class>[] parameterTypes, Object... args) { ClassLoader classLoader = Thread.currentThread().getContextClassLoader();//3.1 Set names = new LinkedHashSet<>( SpringFactoriesLoader.loadFactoryNames(type, classLoader));//3.2 List instances = createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);//3.3 AnnotationAwareOrderComparator.sort(instances);//3.4 return instances; }

3.1 獲取線程上下文ClassLoader

TODO(ClassLoader的相關解釋)

3.2 使用SpringFactoriesLoader加載出classpath下所有路徑為META-INF/spring.factories的資源文件,并讀取key為ApplicationContextInitializer的值

會得到如些幾個類(實際是全稱類名):

SharedMetadataReaderFactoryContextInitializerAutoConfigurationReportLoggingInitializerConfigurationWarningsACIContextIdACIDelegatingACIServerPortInfoACI

3.3 利用反射創建出上述ACI的實例

3.4 排序

根據Ordered接口/@PriorityOrder注解/@Order注解去排

其他地方的排序基本也是按照這個規則來排的

4.設置listener

跟設置ACI的方法一樣,也是讀取spring.factories文件中的對應key項所對應的所有類名,然后實例化、排序.

得到如下幾個ApplicationListener:

BackgroundPreinitializerClearCachesALParentContextCloserALFileEncodingALAnsiOutputALConfigFileALDelegatingALClasspathLoggingALLoggingALLiquibaseServiceLocatorAL

5.設置mainApplicationClass

就是找到main方法所在的類.是唯一的,跟上面的primarySources不是一回事

二.SpringApplication的run(String … args)方法

代碼如下:

public ConfigurableApplicationContext run(String... args) { StopWatch stopWatch = new StopWatch(); stopWatch.start();//1 ConfigurableApplicationContext context = null; Collection exceptionReporters = new ArrayList<>(); configureHeadlessProperty();//2 SpringApplicationRunListeners listeners = getRunListeners(args);//3 listeners.starting();//4 try { ApplicationArguments applicationArguments = new DefaultApplicationArguments( args);//5 ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);//6 configureIgnoreBeanInfo(environment);//7 Banner printedBanner = printBanner(environment);//8 context = createApplicationContext();//9 exceptionReporters = getSpringFactoriesInstances( SpringBootExceptionReporter.class, new Class[] { ConfigurableApplicationContext.class }, context);//10 prepareContext(context, environment, listeners, applicationArguments, printedBanner);//11 refreshContext(context);//12 afterRefresh(context, applicationArguments);//13 listeners.finished(context, null);//14 stopWatch.stop(); //15 if (this.logStartupInfo) { new StartupInfoLogger(this.mainApplicationClass) .logStarted(getApplicationLog(), stopWatch); } callRunners(context, applicationArguments);//16 return context; } catch (Throwable ex) { handleRunFailure(context, listeners, exceptionReporters, ex); throw new IllegalStateException(ex); } }

1. 創建一個StopWatch用于記錄啟動的時間

2. 配置java.awt.headless屬性,默認為true

這個headless是一種模式,是指缺少顯示屏、鍵盤或者鼠標時的系統配置

我找了spring和spring boot的源碼,只有ImageBanner里面用到了

3.從spring.factories中加載出SpringApplicationRunListener,并構建一個SpringApplicationRunListeners

  • StringApplicationListeners就是對對個SpringApplicationRunListener的包裝
  • 現在看只有一個具體實現類
  • EventPublishingRunListener
  • 雖然這個類叫做listener,但其實起的作用是傳播事件,更像是一個ApplicationEventMulticaster。
  • spring boot啟動過程中的事件,主要由這個類來傳播

4.發布一個ApplicationStartingEvent事件

  • 關于spring事件發布機制,請看spring事件機制
  • 響應的AL
  • LoggingAL:初始化日志系統
  • 做法是按照logback>log4j>jul的順序查找classpath下存在的相關類
  • LiquibaseServiceLocatorAL:實在是沒有用過這個東西,不知道這個LiquibaseService是個啥…

5.根據啟動時的命令行參數構建一個ApplicationArguments

ApplicationArguments的接口定義:

public interface ApplicationArguments { String[] getSourceArgs(); //--開頭的參數 Set getOptionNames(); boolean containsOption(String name); //--開頭的參數是允許重復定義的,不會覆蓋 List getOptionValues(String name); List getNonOptionArgs();}

這個類的作用就是解析所有的啟動參數的

6.prepareEnvironment():創建并配置environment

代碼如下:

private ConfigurableEnvironment prepareEnvironment( SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments) { ConfigurableEnvironment environment = getOrCreateEnvironment();//6.1 configureEnvironment(environment, applicationArguments.getSourceArgs());//6.2 listeners.environmentPrepared(environment);//6.3 bindToSpringApplication(environment);//6.4 if (this.webApplicationType == WebApplicationType.NONE) { environment = new EnvironmentConverter(getClassLoader()) .convertToStandardEnvironmentIfNecessary(environment); } ConfigurationPropertySources.attach(environment);//6.5 return environment; }

6.1 根據WebApplicationType創建對應類型的environment

關于spring中Environment/PropertySource的介紹:

根據webApplicationType:

SERVLET -> StandardServletEnvironmentNONE/REACTIVE -> StandardEnvironment

初始化的時候會在構造函數中調用customizePropertySources()方法,其結果是會在environment的propertySources屬性的propertySourcesList列表中加入以下PropertySource:

  • 代表ServletConfig的構建參數的,名為servletConfigInitParams的StubPropertySource(目前只是作為占位符存在)
  • 代表ServletContext的構建參數的,名為servletContextInitParams的StubPropertySource(目前只是作為占位符存在)
  • 代表jvm屬性參數的名為systemProperties的MapPropertySource(來源于System.getProperties()方法)
  • 代表環境變量的名為systemEnvironment的SystemEnvironmentPropertySource(來源于System.getEnv()方法)

6.2 配置environment

配置PropertySources

  • 看看SpringApplication的defaultProperties屬性是否為空,如果不為空則加入一個MapPropertySource到propertySources中。這個defaultProperties屬性可以在SpringApplication調用run方法之前通過setDefaultProperties()方法設置
  • 看看有沒有命令號參數,如果有則創建一個SimpleCommandLinePropertySource加入到propertySources中

配置activeProfiles:就是將spring.profiles.active屬性的值作為數組讀入

6.3 listeners發布一個ApplicationEnvironmentPreparedEvent

這是一個很重要的事件,響應的listener有很多:

ConfigFileApplicationListener

  • 從spring.factories中讀取所有的EnvironmentPostProcessor,它自己也是個EPP。
  • 排序,然后逐個調用
  • SystemEnvironmentPropertySourceEPP:替換systemEnvironment為其內部類OriginAwareSystemEnvironmentPropertySource
  • SpringApplicationJsonEPP:解析spring.application.json屬性,作為JsonPropertySource加入propertySources中

CloudFoundryVcapEPP:VCAP相關,不懂,略過

ConfigFileAL(自己):

  • 添加一個RandomValuePropertySource,作用是設置所有random.int/long開頭的屬性為一個隨機值
  • 從spring.factories中讀取PropertySourceLoader:
  • PropertiesPropertySourceLoader:讀取.properties配置文件
  • YamlPropertySourceLoader:讀取.yaml配置文件
  • 根據activeProfiles解析每個對應的配置文件成OriginTrackedMapPropertySource,加入到propertySources中

6.4 將environment綁定到SpringApplication中

todo…

6.5 往propertySources中加入一個ConfigurationPropertySourcesPropertySource

7.配置一個spring.beaninfo.ignore屬性,默認為true

8.打印banner

9.根據webApplicationType構建ApplicationContext

SERVLET -> AnnotationConfigServletWebServerACREACTIVE -> ReactiveWebServerACNONE -> AnnotationConfigAC

按照繼承結構:

DefaultResourceLoader:ResourceLoader的默認實現,作用就是加載Resource,內部有個比較重要的ProtocolResolver集合屬性,具體使用請看ProtocolResolver解析

AbstractAC:配置了一個ResourcePatternResolver,具體請看Resource相關

GenericAC:初始化了一個BeanFactory,具體類型是DefaultListableBeanFactory

作者:pumpkin_pk

原文鏈接:https://blog.csdn.net/yuxiuzhiai/article/details/79074249

總結

以上是生活随笔為你收集整理的springboot启动过程_spring5/springboot2源码学习 -- spring boot 应用的启动过程的全部內容,希望文章能夠幫你解決所遇到的問題。

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