国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

springboot源碼分析系列(二)--SpringApplication.run()啟動(dòng)流程

adie / 2717人閱讀

摘要:眾所周知,類上面帶有注解的類,即為的啟動(dòng)類。一個(gè)項(xiàng)目只能有一個(gè)啟動(dòng)類。根據(jù)是否是環(huán)境創(chuàng)建默認(rèn)的,通過(guò)掃描所有注解類來(lái)加載和最后通過(guò)實(shí)例化上下文對(duì)象,并返回。

??眾所周知,類上面帶有@SpringBootApplication注解的類,即為springboot的啟動(dòng)類。一個(gè)springboot項(xiàng)目只能有一個(gè)啟動(dòng)類。我們來(lái)分析一下SpringBoot項(xiàng)目的啟動(dòng)過(guò)程,首先看看啟動(dòng)類里面都包含什么

@SpringBootApplication
public class HelloWorldMainApplication {
    public static void main(String[] args) {
        //spring應(yīng)用啟動(dòng)起來(lái)
        SpringApplication.run(HelloWorldMainApplication.class,args);

    }
}

??從上面的代碼中可以看出真正起作用的是SpringApplication.run();這個(gè)方法,下面主要分析一下這個(gè)方法。

一、實(shí)例化SpringApplication

??SpringApplication初始化時(shí)主要做三件事情:

1.根據(jù)classpath下是否存在(ConfigurableWebApplicationContext)判斷是否要啟動(dòng)一個(gè)web applicationContext

2.SpringFactoriesInstances加載classpath下所有可用的ApplicationContextInitializer

3.SpringFactoriesInstances加載classpath下所有可用的ApplicationListener

/**
 * Create a new {@link SpringApplication} instance. The application context will load
 * beans from the specified primary sources (see {@link SpringApplication class-level}
 * documentation for details. The instance can be customized before calling
 * {@link #run(String...)}.
 * @param resourceLoader the resource loader to use
 * @param primarySources the primary bean sources
 * @see #run(Class, String[])
 * @see #setSources(Set)
 */
@SuppressWarnings({ "unchecked", "rawtypes" })
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.根據(jù)classpath下是否存在(ConfigurableWebApplicationContext)判斷是否要啟動(dòng)一個(gè)web applicationContext
    this.webApplicationType = WebApplicationType.deduceFromClasspath();
    //2.SpringFactoriesInstances加載classpath下所有可用的ApplicationContextInitializer
    setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
    //3.SpringFactoriesInstances加載classpath下所有可用的ApplicationListener
    setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
    this.mainApplicationClass = deduceMainApplicationClass();
}
二、實(shí)例化完成后調(diào)用run()方法

??調(diào)用run()方法執(zhí)行的過(guò)程主要分為以下幾步:

1.遍歷SpringApplication初始化過(guò)程中加載的SpringApplicationRunListeners

2.調(diào)用Starting()監(jiān)聽(tīng)SpringApplication的啟動(dòng)

3.加載SpringBoot配置環(huán)境(ConfigurableEnvironment)

4.設(shè)置banner屬性

5.創(chuàng)建ConfigurableApplicationContext(應(yīng)用配置上下文)

6.將listeners、environment、applicationArguments、bannner等重要組件與上下文對(duì)象關(guān)聯(lián)

7.bean的實(shí)力化完成

/**
 * Run the Spring application, creating and refreshing a new
 * {@link ApplicationContext}.
 * @param args the application arguments (usually passed from a Java main method)
 * @return a running {@link ApplicationContext}
 */
public ConfigurableApplicationContext run(String... args) {
    StopWatch stopWatch = new StopWatch();
    stopWatch.start();
    ConfigurableApplicationContext context = null;
    Collection exceptionReporters = new ArrayList<>();
    configureHeadlessProperty();
    //1.遍歷SpringApplication初始化過(guò)程中加載的SpringApplicationRunListeners
    SpringApplicationRunListeners listeners = getRunListeners(args);
    //2.調(diào)用starting()監(jiān)聽(tīng)SpringApplication的啟動(dòng)
    listeners.starting();
    try {
        ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
        //3.加載SpringBoot配置環(huán)境
        ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);
        configureIgnoreBeanInfo(environment);
        //4.設(shè)置banner屬性
        Banner printedBanner = printBanner(environment);
        //5.創(chuàng)建ConfigurableApplicationContext(應(yīng)用配置上下文)
        context = createApplicationContext();
        exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class,
                new Class[] { ConfigurableApplicationContext.class }, context);
        //6.將listeners、environment、applicationArguments、banner等重要組件與上下文對(duì)象關(guān)聯(lián)
        prepareContext(context, environment, listeners, applicationArguments, printedBanner);
        //7.實(shí)例化bean
        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;
}
1.遍歷SpringApplication初始化過(guò)程中加載的SpringApplicationRunListeners
private SpringApplicationRunListeners getRunListeners(String[] args) {
    Class[] types = new Class[] { SpringApplication.class, String[].class };
    return new SpringApplicationRunListeners(logger,
            getSpringFactoriesInstances(SpringApplicationRunListener.class, types, this, args));
}
2.調(diào)用Starting()監(jiān)聽(tīng)SpringApplication的啟動(dòng)
public void starting() {
    //遍歷所有的SpringApplicationRunListener,調(diào)用starting()方法監(jiān)聽(tīng)SpringApplication的啟動(dòng)
    for (SpringApplicationRunListener listener : this.listeners) {
        listener.starting();
    }
}
3.加載SpringBoot配置環(huán)境(ConfigurableEnvironment)

??加載SpringBoot配置環(huán)境(configurableEnvironment),如果是通過(guò)web容器發(fā)布,會(huì)加載StandardEnvironment。將配置文件(Environment)加入到監(jiān)聽(tīng)器對(duì)象中(SpringApplicationRunListeners)

private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners,
        ApplicationArguments applicationArguments) {
    // Create and configure the environment
    //如果environment不為空直接返回 || 如果是web環(huán)境則直接實(shí)例化StandardServletEnvironment類 || 如果不是web環(huán)境則直接實(shí)例化StandardEnvironment類
    ConfigurableEnvironment environment = getOrCreateEnvironment();
    //配置環(huán)境信息
    configureEnvironment(environment, applicationArguments.getSourceArgs());
    //通知所有的監(jiān)聽(tīng)者,環(huán)境已經(jīng)準(zhǔn)備好了
    listeners.environmentPrepared(environment);
    bindToSpringApplication(environment);
    if (!this.isCustomEnvironment) {
        environment = new EnvironmentConverter(getClassLoader()).convertEnvironmentIfNecessary(environment,
                deduceEnvironmentClass());
    }
    ConfigurationPropertySources.attach(environment);
    return environment;
}
4.設(shè)置banner屬性
private Banner printBanner(ConfigurableEnvironment environment) {
    //如果未開(kāi)啟banner打印直接返回
    if (this.bannerMode == Banner.Mode.OFF) {
        return null;
    }
    //創(chuàng)建ResourceLoader對(duì)象
    ResourceLoader resourceLoader = (this.resourceLoader != null) ? this.resourceLoader
            : new DefaultResourceLoader(getClassLoader());
    //創(chuàng)建SpringApplicationBannerPrinter,該對(duì)象用來(lái)打印banner
    SpringApplicationBannerPrinter bannerPrinter = new SpringApplicationBannerPrinter(resourceLoader, this.banner);
    //如果bannerMode模式為L(zhǎng)OG,則將bannner打印到log文件中
    if (this.bannerMode == Mode.LOG) {
        return bannerPrinter.print(environment, this.mainApplicationClass, logger);
    }
    //打印banner到控制臺(tái)
    return bannerPrinter.print(environment, this.mainApplicationClass, System.out);
}
5.初始化ConfigurableApplicationContext(應(yīng)用配置上下文)

??在SpringBoot中,應(yīng)用類型分為三類

public enum WebApplicationType {
    /**
     * The application should not run as a web application and should not start an
     * embedded web server.
     */
    // 應(yīng)用程序不是web應(yīng)用,也不應(yīng)該用web服務(wù)器去啟動(dòng)
    NONE,
    /**
     * The application should run as a servlet-based web application and should start an
     * embedded servlet web server.
     */
    //應(yīng)用程序應(yīng)作為基于servlet的web應(yīng)用程序運(yùn)行,并應(yīng)啟動(dòng)嵌入式servlet web(tomcat)服務(wù)器
    SERVLET,
    /**
     * The application should run as a reactive web application and should start an
     * embedded reactive web server.
     */
    //應(yīng)用程序應(yīng)作為 reactive web應(yīng)用程序運(yùn)行,并應(yīng)啟動(dòng)嵌入式 reactive web服務(wù)器。
    REACTIVE;
}

??根據(jù)webEnvironment是否是web環(huán)境創(chuàng)建默認(rèn)的contextClass,AnnotationConfigEnbeddedWebApplicationContext(通過(guò)掃描所有注解類來(lái)加載bean)和ConfigurableWebApplicationContext),最后通過(guò)BeanUtils實(shí)例化上下文對(duì)象,并返回。

/**
 * Strategy method used to create the {@link ApplicationContext}. By default this
 * method will respect any explicitly set application context or application context
 * class before falling back to a suitable default.
 * @return the application context (not yet refreshed)
 * @see #setApplicationContextClass(Class)
 */
protected ConfigurableApplicationContext createApplicationContext() {
    //根據(jù)webEnvironment是否是web環(huán)境創(chuàng)建默認(rèn)的contextClass
    Class contextClass = this.applicationContextClass;
    if (contextClass == null) {
        try {
            switch (this.webApplicationType) {
            case SERVLET:
                //AnnotationConfigServletWebServerApplicationContext
                contextClass = Class.forName(DEFAULT_SERVLET_WEB_CONTEXT_CLASS);
                break;
            case REACTIVE:
                //AnnotationConfigReactiveWebServerApplicationContext
                contextClass = Class.forName(DEFAULT_REACTIVE_WEB_CONTEXT_CLASS);
                break;
            default:
                //AnnotationConfigApplicationContext
                contextClass = Class.forName(DEFAULT_CONTEXT_CLASS);
            }
        }
        catch (ClassNotFoundException ex) {
            throw new IllegalStateException(
                    "Unable create a default ApplicationContext, " + "please specify an ApplicationContextClass",
                    ex);
        }
    }
    //BeanUtils實(shí)例化上下文對(duì)象
    return (ConfigurableApplicationContext) BeanUtils.instantiateClass(contextClass);
}
6.將listeners、environment、applicationArguments、banner等重要組件與上下文對(duì)象關(guān)聯(lián)
private void prepareContext(ConfigurableApplicationContext context, ConfigurableEnvironment environment,
        SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments, Banner printedBanner) {
    //設(shè)置上下文的environment
    context.setEnvironment(environment);
    //應(yīng)用上下文后處理
    postProcessApplicationContext(context);
    //在context refresh之前,對(duì)其應(yīng)用ApplicationContextInitializer
    applyInitializers(context);
    //上下文準(zhǔn)備
    listeners.contextPrepared(context);
    //打印啟動(dòng)日志和啟動(dòng)應(yīng)用的profile
    if (this.logStartupInfo) {
        logStartupInfo(context.getParent() == null);
        logStartupProfileInfo(context);
    }
    // Add boot specific singleton beans
    ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
    //向beanFactory注冊(cè)單例bean:命令行參數(shù)bean
    beanFactory.registerSingleton("springApplicationArguments", applicationArguments);
    if (printedBanner != null) {
        //向beanFactory注冊(cè)單例bean:banner bean
        beanFactory.registerSingleton("springBootBanner", printedBanner);
    }
    if (beanFactory instanceof DefaultListableBeanFactory) {
        ((DefaultListableBeanFactory) beanFactory)
                .setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
    }
    // Load the sources
    //獲取SpringApplication的primarySources屬性
    Set sources = getAllSources();
    Assert.notEmpty(sources, "Sources must not be empty");
    //將bean加載到應(yīng)用上下文
    load(context, sources.toArray(new Object[0]));
    //向上下文添加ApplicationListener,并廣播ApplicationPreparedEvent事件
    listeners.contextLoaded(context);
}
7.bean的實(shí)例化完成,刷新應(yīng)用上下文           
               
                                           
                       
                 
            
                     
             
               

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/75999.html

相關(guān)文章

  • CommandLineRunner與ApplicationRunner接口的使用及源碼解析

    摘要:實(shí)例定義一個(gè)實(shí)現(xiàn),并納入到容器中進(jìn)行處理啟動(dòng)定義一個(gè)實(shí)現(xiàn),并納入到容器處理應(yīng)用已經(jīng)成功啟動(dòng)啟動(dòng)類測(cè)試,也可以直接在容器訪問(wèn)該值,配置參數(shù),然后執(zhí)行啟動(dòng)類打印結(jié)果接口發(fā)現(xiàn)二者的官方一樣,區(qū)別在于接收的參數(shù)不一樣。引言 我們?cè)谑褂肧pringBoot搭建項(xiàng)目的時(shí)候,如果希望在項(xiàng)目啟動(dòng)完成之前,能夠初始化一些操作,針對(duì)這種需求,可以考慮實(shí)現(xiàn)如下兩個(gè)接口(任一個(gè)都可以) org.springfram...

    tylin 評(píng)論0 收藏0
  • 如何在SpringBoot啟動(dòng)時(shí)執(zhí)行初始化操作,兩個(gè)簡(jiǎn)單接口就可以實(shí)現(xiàn)

    摘要:中有兩個(gè)接口能實(shí)現(xiàn)該功能和。首先了解一下的基本用法,可以在系統(tǒng)啟動(dòng)后執(zhí)行里面的方法執(zhí)行數(shù)據(jù)初始化如果有多個(gè)類的話也可以通過(guò)注解指定每個(gè)類的執(zhí)行順序。 (一)概述 最...

    wuyangnju 評(píng)論0 收藏0
  • 這樣講 SpringBoot 自動(dòng)配置原理,你應(yīng)該能明白了吧

    摘要:這里有一個(gè)參數(shù),主要是用來(lái)指定該配置項(xiàng)在配置文件中的前綴。創(chuàng)建一個(gè)配置類,里面沒(méi)有顯式聲明任何的,然后將剛才創(chuàng)建的導(dǎo)入。創(chuàng)建實(shí)現(xiàn)類,返回的全類名。創(chuàng)建實(shí)現(xiàn)類,實(shí)現(xiàn)方法直接手動(dòng)注冊(cè)一個(gè)名叫的到容器中。前言 小伙伴們是否想起曾經(jīng)被 SSM 整合支配的恐懼?相信很多小伙伴都是有過(guò)這樣的經(jīng)歷的,一大堆配置問(wèn)題,各種排除掃描,導(dǎo)入一個(gè)新的依賴又得添加新的配置。自從有了 SpringBoot 之后,咋...

    cc17 評(píng)論0 收藏0
  • 第三十三章:修改SpringBoot啟動(dòng)Banner

    摘要:本章目標(biāo)修改啟動(dòng)內(nèi)容構(gòu)建項(xiàng)目本章不涉及業(yè)務(wù)邏輯相關(guān)內(nèi)容,簡(jiǎn)單創(chuàng)建一個(gè)框架即可。的隱藏隱藏的方式提供了兩種,不過(guò)其中方式已經(jīng)被拋棄掉了,我們下面介紹下修改配置的方式。 Banner是SpringBoot框架一個(gè)特色的部分,其設(shè)計(jì)的目的無(wú)非就是一個(gè)框架的標(biāo)識(shí),其中包含了版本號(hào)、框架名稱等內(nèi)容,既然SpringBoot為我們提供了這個(gè)模塊,它肯定也是可以更換的這也是Spring開(kāi)源框架的設(shè)計(jì)...

    firim 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<