1. 程式人生 > >SpringBoot啟動過程原理

SpringBoot啟動過程原理

1.1 Springboot啟動:

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

從上面程式碼看,呼叫了SpringApplication的靜態方法run。這個run方法會構造一個SpringApplication的例項,然後再呼叫這裡例項的run方法就表示啟動SpringBoot。具體物件處理流程看下邊時序圖:

概述:

  • 構造SpringApplication的例項(時序圖步驟1-2)
  • 呼叫SpringApplication.run()方法(時序圖步驟3)
    • 構造SpringApplicationRunListeners 例項(時序圖步驟3.1.1)
    • 釋出ApplicationStartedEvent事件(時序圖步驟3.1.2)
    • SpringApplicationRunListeners 例項準備環境資訊(時序圖步驟3.1.3)
    • 建立ApplicationContext物件(時序圖步驟3.1.4)
    • ApplicationContext例項準備環境資訊(時序圖步驟3.1.5)
    • 重新整理的上下文(時序圖步驟3.1.6)

注:文章按照該順序講解【1.2 啟動載入過程分析】

時序圖:
這裡寫圖片描述

1.2 啟動載入過程分析

1.2.1 構造SpringApplication的例項(時序圖步驟1-2)

程式碼

public static ConfigurableApplicationContext run(Object[] sources, String[] args) {
        // 步驟1
        return new SpringApplication(sources).run(args);
}
public SpringApplication(Object... sources) {
        // 步驟1.1
initialize(sources); } @SuppressWarnings({ "unchecked", "rawtypes" }) private void initialize(Object[] sources) { if (sources != null && sources.length > 0) { this.sources.addAll(Arrays.asList(sources)); } this.webEnvironment = deduceWebEnvironment(); //載入META-INF/spring.factories路徑ApplicationContextInitializer.class getSpringFactoriesInstances( ApplicationContextInitializer.class)); setListeners((Collection) //載入META-INF/spring.factories路徑ApplicationListener.class getSpringFactoriesInstances(ApplicationListener.class)); this.mainApplicationClass = deduceMainApplicationClass(); }

分析
⑴.通過ClassLoader.getResources載入META-INF/spring.factories路徑下的
檔案資訊,從中找key為ApplicationContextInitializer.class,並例項化。
⑵.通過ClassLoader.getResources載入META-INF/spring.factories路徑下的
檔案資訊ApplicationListener.class對應類,並例項化。

1.2.2 呼叫SpringApplication.run()方法(時序圖步驟3)

程式碼:

public ConfigurableApplicationContext run(String... args) {
        StopWatch stopWatch = new StopWatch();
        stopWatch.start();
        ConfigurableApplicationContext context = null;
        FailureAnalyzers analyzers = null;
        configureHeadlessProperty();
        //  步驟3.1.1
        SpringApplicationRunListeners listeners = getRunListeners(args);
        // 步驟3.1.2
        listeners.starting();
        try {
            ApplicationArguments applicationArguments = new DefaultApplicationArguments(
                    args);
            // 步驟 3.1.3
            ConfigurableEnvironment environment = prepareEnvironment(listeners,
                    applicationArguments);
            Banner printedBanner = printBanner(environment);
            // 步驟3.1.4
            context = createApplicationContext();
            analyzers = new FailureAnalyzers(context);
            // 步驟3.1.5
            prepareContext(context, environment, listeners, applicationArguments,
                    printedBanner);
            // 步驟3.1.6
            refreshContext(context);
            // 步驟3.1.7
            afterRefresh(context, applicationArguments);
            // 步驟3.1.8
            listeners.finished(context, null);
            stopWatch.stop();
            if (this.logStartupInfo) {
                new StartupInfoLogger(this.mainApplicationClass)
                        .logStarted(getApplicationLog(), stopWatch);
            }
            return context;
        }
        catch (Throwable ex) {
            handleRunFailure(context, listeners, analyzers, ex);
            throw new IllegalStateException(ex);
        }
    }
1.2.2 步驟3.1.1:

程式碼

private SpringApplicationRunListeners getRunListeners(String[] args) {
        Class<?>[] types = new Class<?>[] { SpringApplication.class, String[].class };
        // (1)
        return new SpringApplicationRunListeners(logger, getSpringFactoriesInstances(
                SpringApplicationRunListener.class, types, this, args));
    }

分析
(1). 通過ClassLoader.getResources載入META-INF/spring.factories路徑下的
檔案資訊,從中找key為SpringApplicationRunListener對應類,並例項化。

1.2.3 步驟3.1.2:

程式碼

public void starting() {
        for (SpringApplicationRunListener listener : this.listeners) {
            listener.starting();
        }
    }
    @Override
    @SuppressWarnings("deprecation")
    public void starting() {
        this.initialMulticaster
                .multicastEvent(new ApplicationStartedEvent(this.application, this.args));
    }

分析
釋出ApplicationStartedEvent事件。

1.2.4 步驟3.1.3:

程式碼

private ConfigurableEnvironment prepareEnvironment(
            SpringApplicationRunListeners listeners,
            ApplicationArguments applicationArguments) {
        // Create and configure the environment
        // ⑴. 得到環境物件ConfigurableEnvironment
        ConfigurableEnvironment environment = getOrCreateEnvironment();
        // ⑵. 並配置環境資訊;對listeners初始化環境屬性
        configureEnvironment(environment, applicationArguments.getSourceArgs());
        // ⑶. 釋出ApplicationEnvironmentPreparedEvent事件。
        listeners.environmentPrepared(environment);
        if (isWebEnvironment(environment) && !this.webEnvironment) {
            environment = convertToStandardEnvironment(environment);
        }
        return environment;
    }

分析
⑴. 得到環境物件ConfigurableEnvironment
⑵. 並配置環境資訊;對listeners初始化環境屬性。
⑶. 釋出ApplicationEnvironmentPreparedEvent事件。

步驟3.1.4:

分析
建立ApplicationContext物件 ,其中在例項化ApplicationContext子類
AnnotationConfigApplicationContext時,如程式碼:

public AnnotationConfigApplicationContext() {
        this.reader = new AnnotatedBeanDefinitionReader(this);
        this.scanner = new ClassPathBeanDefinitionScanner(this);
}

會建立AnnotatedBeanDefinitionReader物件檢測是否需要將一下物件放到Spring上下文中

// 使用者配置Configuration註解,實現了BeanDefinitionRegistryPostProcessor介面
ConfigurationClassPostProcessor
// 用於配置Autowired註解,實現了MergedBeanDefinitionPostProcessor介面
AutowiredAnnotationBeanPostProcessor
// 用於配置Required註解,實現了MergedBeanDefinitionPostProcessor介面
RequiredAnnotationBeanPostProcessor
// 用於配置JSR-250註解,實現了InstantiationAwareBeanPostProcessor介面
CommonAnnotationBeanPostProcessor
// 用於配置JPA註解
PersistenceAnnotationBeanPostProcessor
// 用於配置EventListener註解,實現了SmartInitializingSingleton介面
EventListenerMethodProcessor
// EventListener工廠
DefaultEventListenerFactory
步驟3.1.5:

程式碼

private void prepareContext(ConfigurableApplicationContext context,
            ConfigurableEnvironment environment, SpringApplicationRunListeners listeners,
            ApplicationArguments applicationArguments, Banner printedBanner) {
        // ⑴.對ApplicationContext設定環境變數;
        context.setEnvironment(environment);
        // ⑵.配置屬性ResourceLoader和ClassLoader屬性;
        postProcessApplicationContext(context);
        // ⑶.迴圈初始化繼承了
        applyInitializers(context);
        listeners.contextPrepared(context);
        if (this.logStartupInfo) {
            logStartupInfo(context.getParent() == null);
            logStartupProfileInfo(context);
        }

        // Add boot specific singleton beans
        context.getBeanFactory().registerSingleton("springApplicationArguments",
                applicationArguments);
        if (printedBanner != null) {
            context.getBeanFactory().registerSingleton("springBootBanner", printedBanner);
        }

        // Load the sources
        Set<Object> sources = getSources();
        Assert.notEmpty(sources, "Sources must not be empty");
        load(context, sources.toArray(new Object[sources.size()]));
        listeners.contextLoaded(context);
    }

分析:
⑴.對ApplicationContext設定環境變數;
⑵.配置屬性ResourceLoader和ClassLoader屬性;
⑶.呼叫步驟1查詢出來ApplicationContextInitializer子類,迴圈呼叫initialize()方法。

@SuppressWarnings({ "rawtypes", "unchecked" })
    protected void applyInitializers(ConfigurableApplicationContext context) {
        for (ApplicationContextInitializer initializer : getInitializers()) {
            Class<?> requiredType = GenericTypeResolver.resolveTypeArgument(
                    initializer.getClass(), ApplicationContextInitializer.class);
            Assert.isInstanceOf(requiredType, context, "Unable to call initializer.");
            initializer.initialize(context);
        }
    }

⑷.釋出ApplicationPreparedEvent事件。

步驟3.1.6

程式碼:

@Override
    public void refresh() throws BeansException, IllegalStateException {
        synchronized (this.startupShutdownMonitor) {
            // ⑴.準備重新整理的上下文環境
            prepareRefresh();

            // ⑵.初始化BeanFactory
            ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

            // ⑶.對BeanFactory進行各種功能填充
            prepareBeanFactory(beanFactory);

            try {
                // ⑷.子類覆蓋方法做額外的處理
                postProcessBeanFactory(beanFactory);

                // ⑸.啟用各種BeanFactory處理器
                invokeBeanFactoryPostProcessors(beanFactory);

                // ⑹.註冊攔截Bean建立的Bean處理,這裡只是註冊,真正呼叫是再拿去Bean的時候
                registerBeanPostProcessors(beanFactory);

                // ⑺.為上下文初始化Message源,即不同語言的訊息體,國際化處理
                initMessageSource();

                // ⑻.初始化應用訊息廣播器,並放到applicationEventMulticaster bean中
                initApplicationEventMulticaster();

                // ⑼.留給子類來初始化其他bean
                onRefresh();

                // ⑽.在所有註冊的bean中查詢Listener bean,註冊到訊息廣播中
                registerListeners();

                // ⑾.初始化剩下的單例項(非惰性)
                finishBeanFactoryInitialization(beanFactory);

                // ⑿.完成重新整理過程,通知生命週期處理器lifecycleProcessor重新整理過程,同時發出ContextRefreshEvent通知別人
                finishRefresh();
            }

            catch (BeansException ex) {
                if (logger.isWarnEnabled()) {
                    logger.warn("Exception encountered during context initialization - " +
                            "cancelling refresh attempt: " + ex);
                }

                // Destroy already created singletons to avoid dangling resources.
                destroyBeans();

                // Reset 'active' flag.
                cancelRefresh(ex);

                // Propagate exception to caller.
                throw ex;
            }

            finally {
                // Reset common introspection caches in Spring's core, since we
                // might not ever need metadata for singleton beans anymore...
                resetCommonCaches();
            }
        }
    }

分析:

⑴.準備重新整理的上下文環境
⑵.初始化BeanFactory
⑶.對BeanFactory進行各種功能填充
⑷.子類覆蓋方法做額外的處理
⑸.啟用各種BeanFactory處理器
⑹.註冊攔截Bean建立的Bean處理,這裡只是註冊,真正呼叫是再拿去Bean的時候
⑺.為上下文初始化Message源,即不同語言的訊息體,國際化處理
⑻.初始化應用訊息廣播器,並放到applicationEventMulticaster bean中
⑼.留給子類來初始化其他bean
⑽.在所有註冊的bean中查詢Listener bean,註冊到訊息廣播中
⑾.初始化剩下的單例項(非惰性)
⑿.完成重新整理過程,通知生命週期處理器lifecycleProcessor重新整理過程,同時發出ContextRefreshEvent通知別人

容器重新整理