一马平川
不积跬步无以至千里,后继才能薄发

Springboot启动过程笔记

2021年05月21日
0
未分类

之前看了springIOC源码,现在结合Springboot整体启动过程来看这个

重要的时间回调机制

ApplicationContextInitializer

上下文初始化器,在创建出上下文之后被执行

SpringApplicationRunListener

应用启动监听器,在各个阶段的方法,在spring启动到指定时期回调

ApplicationRunner

CommandLineRunner

用于自定义创建IOC容器完成后的操作,入参是命令行参数

自定义回调机制

ApplicationContextInitializerSpringApplicationRunListener 自定义需要在当前项目下的 META-INF/spring.factories 配置文件中加入自定义的实现类

关键类:

SpringApplication :应用

SpringApplicationContext :应用上下文

SpringApplicationRunListener :应用运行监听器

启动步骤:

  1. 调用SpringApplication 的静态方法 run 方法

  2. run 方法创建 SpringApplication 实例,这里用到了工厂模式,并通过 initialize 方法初始化,其中从META-INF/spring.factories 中获取 ApplicationContextInitializer 应用上下文初始化器的子类全限名,然后通过ClassLoader实例化,获取到的初始化器列表存储起来,然后通过同样的方法实例化监听器

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    @SuppressWarnings({ "unchecked", "rawtypes" })
    private void initialize(Object[] sources) {
    if (sources != null && sources.length > 0) {
    this.sources.addAll(Arrays.asList(sources));
    }
    //判断是否web环境
    this.webEnvironment = deduceWebEnvironment();
    //存储实例化的初始化器列表
    setInitializers((Collection) getSpringFactoriesInstances(
    ApplicationContextInitializer.class));
    //存储实例化的监听器列表
    setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
    this.mainApplicationClass = deduceMainApplicationClass();
    }
  3. 然后通过实例方法 run

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    public ConfigurableApplicationContext run(String... args) {
    StopWatch stopWatch = new StopWatch();
    stopWatch.start();
    ConfigurableApplicationContext context = null;
    FailureAnalyzers analyzers = null;
    configureHeadlessProperty();
    // 从META-INF/spring.factories获取 SpringApplicationRunListeners
    SpringApplicationRunListeners listeners = getRunListeners(args);
    // 把所有的Listeners都启动
    listeners.starting();
    try {
    // 封装命令行参数
    ApplicationArguments applicationArguments = new DefaultApplicationArguments(
    args);
    // 准备环境,激活哪个profile在这里读取,
    ConfigurableEnvironment environment = prepareEnvironment(listeners,
    applicationArguments);
    // 打印横幅图标
    Banner printedBanner = printBanner(environment);
    // 判断是否web环境,然后通过反射创建IOC容器
    context = createApplicationContext();
    // 异常分析报告
    analyzers = new FailureAnalyzers(context);
    // 准备上下文环境,把environment设进context,然后获取之前保存的初始化器,
    // 调用初始化器的initialize()方法对context进行初始化,初始化完成之后,
    // 回调SpringApplicationRunListener监听器
    prepareContext(context, environment, listeners, applicationArguments,
    printedBanner);
    // 刷新(初始化)容器,加载IOC容器所有配置的组件,如果是web应用还会创建内置tomcat
    refreshContext(context);
    // 从IOC容器中获取所有ApplicationRunner.class 、CommandLineRunner.class
    // 优先调用前一个回调,再回调另一个
    afterRefresh(context, applicationArguments);
    // 所有的ApplicationRunListener回调finished()方法
    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);
    }
    }

    prepareContext()

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    private void prepareContext(ConfigurableApplicationContext context,
    ConfigurableEnvironment environment, SpringApplicationRunListeners listeners,
    ApplicationArguments applicationArguments, Banner printedBanner) {
    //把environment保存入context,如默认profile和激活profile等
    context.setEnvironment(environment);
    //对context进行
    postProcessApplicationContext(context);
    applyInitializers(context);
    listeners.contextPrepared(context);
    if (this.logStartupInfo) {
    logStartupInfo(context.getParent() == null);
    logStartupProfileInfo(context);
    }

    // 注册命令行参数到springApplicationArguments单例实例
    context.getBeanFactory().registerSingleton("springApplicationArguments",
    applicationArguments);
    //注册横幅到springBootBanner单例实例
    if (printedBanner != null) {
    context.getBeanFactory().registerSingleton("springBootBanner", printedBanner);
    }

    // 获取springboot入口类
    Set<Object> sources = getSources();
    Assert.notEmpty(sources, "Sources must not be empty");
    //
    load(context, sources.toArray(new Object[sources.size()]));
    listeners.contextLoaded(context);
    }

如果喜欢这篇文章,可以给作者评个份哦~

原文声明: "转载本站文章请注明作者和出处Nothinglin ,请勿用于任何商业用途"

公众号:苦逼的学生仔