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

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 综合教程 >内容正文

综合教程

SpringBoot启动过程解析(简化)

發布時間:2024/4/24 综合教程 40 生活家
生活随笔 收集整理的這篇文章主要介紹了 SpringBoot启动过程解析(简化) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

springBoot web方式啟動過程

在這個啟動過程中會有各種SpringBoot對外提供的擴展接口來對不同啟動階段進行自定義操作。
了解啟動過程也是為了讓我們更好理解SpringBoot提供的擴展接口使用


jar包啟動或者外置war包啟動都是調用SpringApplication.run()方法進行項目啟動

tomcat會查詢context上下文中實現ServletContainerInitializer接口的類,然后調用類的onStartup(Set<Class<?>> c, ServletContext ctx)方法
Spring的SpringServletContainerInitializer實現了這個ServletContainerInitializer接口,
會獲取WebApplicationInitializer接口的實現類,調用onStartup()方法

SpringBoot的類SpringBootServletInitializer實現了Spring的WebApplicationInitializer擴展接口,
會在onStartup()方法中創建SpringApplication類,并調用SpringApplication.run()來完成啟動項目
與我們在開發時調用Application.main()方法啟動時一樣的原理

開始分析

@SpringBootApplication
public class Application extends SpringBootServletInitializer {

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }

    @Override
    protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {
        this.setRegisterErrorPageFilter(false); // 錯誤頁面有容器來處理,而不是SpringBoot
        return builder.sources(Application.class);
    }

}

1、SpringApplication構造方法
初始化 ApplicationListener 和 ApplicationContextInitializer,還有設置應用類型:默認為WebApplicationType.SERVLET 即servlet容器

接著執行SpringApplication.run()方法
在這個方法里面總的概述就是對上下文和環境進行初始化配置,application上下文的BeanFactory管理bean定義和bean的初始化過程。。

public ConfigurableApplicationContext run(String... args) {
        StopWatch stopWatch = new StopWatch();
        stopWatch.start();
        ConfigurableApplicationContext context = null;
        Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
        configureHeadlessProperty();
        SpringApplicationRunListeners listeners = getRunListeners(args);
        listeners.starting();
        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);
        }

        try {
            listeners.running(context);
        }
        catch (Throwable ex) {
            handleRunFailure(context, ex, exceptionReporters, null);
            throw new IllegalStateException(ex);
        }
        return context;
    }

2 、觸發ApplicationStartingEvent事件

SpringBoot對Spring的ApplicationListener進行了一個包裝

在啟動過程中使用SpringApplicationRunListener接口的實現類EventPublishingRunListener來觸發各種事件

public interface SpringApplicationRunListener {
    starting ==> ApplicationStartingEvent
    environmentPrepared ==> ApplicationEnvironmentPreparedEvent
    contextPrepared ==> 無
    contextLoaded ==》 ApplicationPreparedEvent
    started ==》 ApplicationStartedEvent
    running ==》 ApplicationReadyEvent
    failed ==》 ApplicationFailedEvent
}

我們可以通過自定義SpringApplicationRunListener來在不同階段操作,也可以通過配置ApplicationListener來完成不同階段的操作。

這個開始啟動事件觸發操作:主要是進行日志系統初始化,字符集設置等操作

最開始觸發的監聽器:LoggingApplicationListener和BackgroundPreinitializer

LoggingApplicationListener日志系統實例生成,執行初始化前方法loggingSystem.beforeInitialize()
BackgroundPreinitializer 后臺線程預初始化任務,用于耗時任務的初始化
1.默認類型轉換器,format格式解析初始化
2.初始化校驗器
3. 默認處理表單數據的消息轉換器初始化的AllEncompassingFormHttpMessageConverter
4.初始化tomcat的MBeanFactory
5. 字符集初始化

3、獲取命令行參數和準備上下文環境

prepareEnvironment(listeners, applicationArguments)

初始化systemProperties,systemEnvironment屬性源。獲取系統屬性設置到環境中

這個方法里觸發ApplicationEnvironmentPreparedEvent環境準備完成事件監聽器

主要是ConfigFileApplicationListener監聽這個事件
會調用EnvironmentPostProcessor 環境后置處理器接口
還有這個類本身后置處理器會將配置文件加載到environment環境的屬性源列表中

環境準備事件觸發操作:配置文件屬性源加載,日志系統配置環境屬性設置

EnvironmentPostProcessor 這個接口擴展處理上下文環境操作

DelegatingApplicationListener,這個委托代理監聽器只能代理ApplicationEnvironmentPreparedEvent環境準備完成事件

4、初始化上下文信息

prepareContext(context, environment, listeners, applicationArguments, printedBanner);

為context上下文設置reader和scanner,用于獲取bean定義
調用ApplicationContextInitializer接口,對上下文進行初始化
將ApplicationArguments和SpringApplication作為bean注冊到BeanFactory中
load(context, sources.toArray(new Object[0])); 這里是將應用啟動類,即Application.java類,將其生成BeanDefinition即bean定義,綁定到beanFactory中
觸發ApplicationPreparedEvent事件

ApplicationContextInitializer接口, 對上下文進行初始化操作

觸發ApplicationPreparedEvent事件

網上資料:ApplicationPreparedEvent事件:在Bean定義加載之后、bean初始化之前,刷新上下文之前觸發

自己調試:這個bean定義加載只是對Application.java啟動類和內置的bean定義進行加載,我們項目中自定義的bean定義還是沒有進行加載。

ApplicationPreparedEvent事件觸發操作:

將ConfigFileApplicationListener # PropertySourceOrderingPostProcessor添加到ApplicationContext的BeanFactoryPostProcessors列表中,這個是BeanFactory的后置處理器
將Bean名稱為:“springBootLoggingSystem”日志系統注冊到beanfactory中

注意:在這里所有自定義的Bean定義都還沒有開始加載,這個進行自定義獲取bean是無效的


5、刷新上下文
refreshContext(context);

這個是spring啟動過程中最多邏輯的階段

5.1、 prepareRefresh()

設置系統啟動標志為啟動,以及屬性校驗等操作

5.2、prepareBeanFactory(beanFactory)

配置beanfactory
設置bean類加載器,設置SpEL表達式解析器,注冊配置屬性編輯器,
初始化BeanPostProcessor(如ApplicationContextAwareProcessor),
設置忽略自動裝配的接口,
注冊默認環境bean(environment,systemProperties,systemEnvironment)

設置忽略自動裝配的接口是Spring默認指定的Aware及其子接口

當類A中有屬性是類B時,在初始化A的bean時,
如果類B是實現了Aware或其子接口時。不會為A自動注入類B
而是要通過B實現了Aware其子接口的接口方法來為A設置屬性
一般來說:實現了Aware其子接口的實現類都是作為工具類,或者配置類

BeanPostProcessor接口:對bean初始化前后做一些操作邏輯,比如設置bean的屬性,或對特殊的bean的方法進行調用等

5.3postProcessBeanFactory(beanFactory)

context的子類在配置好BeanFactory后的擴展方法,

這里是AnnotationConfigServletWebServerApplicationContext類
添加了一個后置處理器,一個忽略自動注入接口
beanFactory.addBeanPostProcessor(WebApplicationContextServletContextAwareProcessor) beanFactory.ignoreDependencyInterface(ServletContextAware.class)

5.4invokeBeanFactoryPostProcessors(beanFactory)

回調BeanFactoryPostProcessor處理器
在這里會進行bean定義的加載

會將ApplicationContext中設置的beanFactoryPostProcessors列表
轉換成BeanDefinitionRegistryPostProcessor(registryProcessors 注冊處理器) 和BeanFactoryPostProcessor(regularPostProcessors 規則處理器)

內置beanFactory后置處理器列表

SharedMetadataReaderFactoryContextInitializer # CachingMetadataReaderFactoryPostProcessor
ConfigurationWarningsApplicationContextInitializer # ConfigurationWarningsPostProcessor
ConfigFileApplicationListener # PropertySourceOrderingPostProcessor

會先調用內置的注冊處理器的postProcessBeanDefinitionRegistry(registry);方法
進行自定義bean的注冊,或者對beanFactory中的bean定義的屬性值進行修改

比如

SharedMetadataReaderFactoryContextInitializer # CachingMetadataReaderFactoryPostProcessor
會將SharedMetadataReaderFactoryContextInitializer.SharedMetadataReaderFactoryBean類創建bean定義注冊到BeanFactory中,
還有修改ConfigurationAnnotationProcessor類的metadataReaderFactory屬性值為SharedMetadataReaderFactoryBean


(重點)執行完后置處理器的注冊方法后,會獲取到Beanfactory中綁定的BeanDefinitionRegistryPostProcessor
也就是ConfigurationClassPostProcessor,調用它的postProcessBeanDefinitionRegistry(registry)方法
這個類會將Spring注解標記的Bean定義解析綁定到BeanFactory中

也就是說只要有@Configuration、@Component、@ComponentScan、@Import、@ImportResource和@Bean中的其中一個注解,就會將bean注冊到beanfactory中
@Import注解處理,如果導入的是ImportSelector接口實現類,會調用接口方法String[] selectImports()
通過返回字符串數組。里面是配置類名稱。動態選擇要導入的配置類全名

除了解析上面注解定義的bean外

還會處理@PropertySource注解,將指定的配置屬性源設置到environment環境中

this.reader.loadBeanDefinitions(configClasses);這里會進行額外的bean定義加載:(被Import導入的類加載,方法定義的bean加載,資源文件中定義的bean)

后置處理器處理過程中會被調用三次

1. 第一次是執行ConfigurationClassPostProcessor后置處理器,獲取項目中的bean定義
執行過了后置處理器不會再次執行
2. 第二次是在所有bean定義中獲取有加@Order注解的BeanDefinitionRegistryPostProcessor實現類,執行后置處理器。
3. 第三次是再次獲取沒有執行過的處理器進行再次執行
比如mybatis的MapperScannerConfigurer就是在這里執行實現mybatis注解的bean定義加載
4. 最后是執行registryProcessors注冊器和regularPostProcessors規則處理器的postProcessBeanFactory(beanFactory)方法

實現不同接口分類按從上到下執行

PriorityOrdered接口
PropertySourcesPlaceholderConfigurer

Ordered接口

沒有實現上面接口的
org.springframework.boot.context.properties.ConfigurationBeanFactoryMetadata
preserveErrorControllerTargetClassPostProcessor
dataSourceInitializerSchedulerDependencyPostProcessor

5.5、registerBeanPostProcessors(beanFactory);

從beanFactory獲取BeanPostProcessor分別按照PriorityOrdered,Ordered,普通的類型順序注冊BeanPostProcessor

beanFactory.addBeanPostProcessor(postProcessor)

5.6、initMessageSource():一般是我們用來初始化我們國際化文件的

5.7、initApplicationEventMulticaster(); 初始化事件廣播器

5.8、onRefresh():初始化其他的子容器類中的bean,同時創建spring的內置tomcat,

ServletWebServerApplicationContext.onRefresh()在這里創建createWebServer
這里會調用tomcat的內置啟動流程tomcat.start()
StandardServer->StandardService->StandardEngine(servlet引擎)->StandardHost(可以理解為ip+端口號)->StandardContext(這里就是我們的項目)

5.9、registerListeners():

添加用戶設置applicationListeners,然后從beanFactory獲取ApplicationListener,
然后發布需要earlyApplicationEvents事件

是從beanFactory中獲取所有實現ApplicationListener接口的類,
getBeanNamesForType(ApplicationListener.class, true, false)
第一個type參數表示類型,第二個參數是否包含非單例的bean
第三個參數是否允許提前初始化, true表示允許。會導致bean提前初始化,
false,表示不允許提前初始化,如果實在spring啟動過程中,這個參數需要設置為false

6.0、finishBeanFactoryInitialization(beanFactory);

緩存所有bean定義元數據 bean definition metadata
beanFactory.preInstantiateSingletons();
實例化所有剩余的(非延遲初始化)單例。
在這個過程中會調用beanPostProcessors,bean實例化前后的處理器

調用AbstractAutowireCapableBeanFactory的 initializeBean(beanName, exposedObject, mbd);方法

在這個方法里會處理實現Aware接口的Bean類
invokeAwareMethods(beanName, bean);方法會處理實現了BeanNameAware,BeanClassLoaderAware,BeanFactoryAware接口實現了類的接口方法

接著調用applyBeanPostProcessorsBeforeInitialization 處理BeanPostProcessor bean調用初始化之前的處理
接著調用bean的初始化方法invokeInitMethods(beanName, wrappedBean, mbd);
接著調用bean的初始化方法之后的后置處理器

ApplicationContextAwareProcessor:

處理實現EnvironmentAware,EmbeddedValueResolverAware,ResourceLoaderAware,ApplicationEventPublisherAware,MessageSourceAware,ApplicationContextAware這些接口的實現bean類在
在初始化回調之前調用對應接口方法做對應的操作。
比如initializingBean的afterPropertiesSet()方法之前或@Bean注解設置的init-method之前調用

WebApplicationContextServletContextAwareProcessor

處理實現了ServletContextAware接口的bean,可以通過setServletContext(ServletContext)方法獲取servletContext

6.1、finishRefresh();

完成上下文刷新,
清除上下文級別的resources緩存(MetadataReader封裝的資源,比如掃描的配置類)
初始化lifecycleProcessor,用來管理spring生命周期的onRefresh作用是容器啟動成功,onClose是只應用要關閉的時候

然后觸發ContextRefreshedEvent事件

refreshContext(context);執行完成

到這里spring項目容器已經啟動成功

7、afterRefresh(context, applicationArguments);

這里沒有操作

8、觸發ApplicationStartedEvent事件

9、callRunners(context, applicationArguments)

從beanfactory中獲取ApplicationRunner和CommandLineRunner接口實現類
調用他們的run方法

10、觸發ApplicationReadyEvent事件

啟動完成

作者:海綿般汲取
出處:https://www.cnblogs.com/gne-hwz/
版權:本文版權歸作者和博客園共有
轉載:歡迎轉載,但未經作者同意,必須保留此段聲明;必須在文章中給出原文連接;否則必究法律責任

總結

以上是生活随笔為你收集整理的SpringBoot启动过程解析(简化)的全部內容,希望文章能夠幫你解決所遇到的問題。

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