Spring Boot启动过程分析

以一个web工程启动为例, maven中引入

<dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-web</artifactId>
</dependency>

 

示例启动类:

package com.simple.boot;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

/**
 * @author LILE
 */
@SpringBootApplication
public class SimpleBootApplication {
    public static void main(String[] args) {
        SpringApplication.run(SimpleBootApplication.class);
    }

}

 

SpringApplication.run是调用静态run方法启动, 内部会创建SpringApplication实例, 并通过实例调用非静态run方法, run方法有几种重载形式, 我们只关注最终的调用:

new SpringApplication(sources).run(args)

SpringApplication是SpringBoot程序的入口, 启动SpringBoot首先会实例化SpringApplication对象, SpringApplication最重要的功能是创建并初始化AppliactionContext, 下面就分别分析new SpringApplication和run方法

一、 new SpringApplication(sources):

Tips: sources参数就是[SimpleBootApplication.class]

SpringApplication用于启动一个SpringBoot程序,  它允许我们自定义ApplicationContextInitializer 和ApplicationListener, 用于在SpringBoot启动时的不同阶段, 执行自定义代码, 而SpringApplication的构造器中, 主要就负责读取并实例化这些监听对象。

  SpringApplication构造器主要逻辑代码(均位于SpringApplication.java):

    248:this.webEnvironment = deduceWebEnvironment();    // 判断是否是WEB环境, 返回boolean值, "javax.servlet.Servlet", "org.springframework.web.context.ConfigurableWebApplicationContext", 看这两个类信息是否能加载到
    249:setInitializers((Collection) getSpringFactoriesInstances(    
            ApplicationContextInitializer.class));    // 设置this.initializers, 均实现ApplicationContextInitializer接口
    251:setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));    // 设置this.listeners, 均实现ApplicationListener接口
    252:this.mainApplicationClass = deduceMainApplicationClass();    // 找到main方法对应的类, 这里是SimpleBootApplication.class

249、251都是调用 getSpringFactoriesInstances, 该方法作用如下:
1、从类路径的 META-INF/spring.factories文件加载所有类定义
2、按类型条件过滤出指定Class定义, 如249过滤出ApplicationContextInitializer实现类, 251过滤出ApplicationListener实现类
3、实例化这些类, BeanUtils.instantiateClass
4、对实例排序 AnnotationAwareOrderComparator.sort(instances);

new SpringApplication的主要逻辑就执行完成了, 可以通过断点, 看下最终值:

    this.sources = [SimpleBootApplication.class];
    this.webEnvironment = true;
    
    // ApplicationContext初始化实现类, 在run方法中会被调用
    this.initializers = [
        0 = {DelegatingApplicationContextInitializer@1109} 
        1 = {ContextIdApplicationContextInitializer@1110} 
        2 = {ConfigurationWarningsApplicationContextInitializer@1111} 
        3 = {ServerPortInfoApplicationContextInitializer@1112} 
        4 = {SharedMetadataReaderFactoryContextInitializer@1113} 
        5 = {AutoConfigurationReportLoggingInitializer@1114} 
    ];
    
    // 监听器, 在run方法中会被调用
    this.listeners = [    
        0 = {ConfigFileApplicationListener@1098} 
        1 = {AnsiOutputApplicationListener@1099} 
        2 = {LoggingApplicationListener@1100} 
        3 = {ClasspathLoggingApplicationListener@1101} 
        4 = {BackgroundPreinitializer@1102} 
        5 = {DelegatingApplicationListener@1103} 
        6 = {ParentContextCloserApplicationListener@1104} 
        7 = {ClearCachesApplicationListener@1105} 
        8 = {FileEncodingApplicationListener@1106} 
        9 = {LiquibaseServiceLocatorApplicationListener@1107} 
    ];
    
    // 主函数所在的类
    this.mainApplicationClass = SimpleBootApplication.class;

  这些initializers, listeners将在run方法中, 不同的时机调用。

二、run(args) :

run方法的执行逻辑几乎都是围绕着ApplicationContext, 从ApplicationContext预处理、创建、完成创建: 

    public ConfigurableApplicationContext run(String... args) {
        StopWatch stopWatch = new StopWatch();
        stopWatch.start();
        ConfigurableApplicationContext context = null;
        FailureAnalyzers analyzers = null;
        configureHeadlessProperty();
    291:SpringApplicationRunListeners listeners = getRunListeners(args);
    292:listeners.starting();
        try {
            ApplicationArguments applicationArguments = new DefaultApplicationArguments(
                    args);
        296:ConfigurableEnvironment environment = prepareEnvironment(listeners,
                    applicationArguments);
        298:Banner printedBanner = printBanner(environment);
        299:context = createApplicationContext();
            analyzers = new FailureAnalyzers(context);
        301:prepareContext(context, environment, listeners, applicationArguments,
                    printedBanner);
        303:refreshContext(context);
        304:afterRefresh(context, applicationArguments);
        305: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);
        }
    }

 

posted @ 2018-03-27 17:19  昵称有毒  阅读(183)  评论(0编辑  收藏  举报