Spring Boot 源码分析三:深入探讨 SpringApplication 类及其子组件

1. 引言

在前两篇文章中,我们介绍了SpringBoot的启动流程,并深入分析了启动流程中的核心方法。本篇文章将进一步探讨SpringApplication类及其子组件,分析它们在启动过程中所扮演的角色和实现细节。

2. SpringApplication 子组件解析

2.1ApplicationContextInitializer 接口

ApplicationContextInitializer是一个接口,用于在Spring应用上下文刷新之前对其进行进一步的配置。

2.1.1 定义
public interface ApplicationContextInitializer<C extends ConfigurableApplicationContext> {
    void initialize(C applicationContext);
}
  • 功能:initialize方法在应用上下文刷新之前被调用,用于对上下文进行自定义初始化。

2.1.2 使用

在SpringApplication的构造方法中,会加载所有 ApplicationContextInitializer 实现类:

public SpringApplication(Class<?>... primarySources) {
    this.setInitializers((Collection) this.getSpringFactoriesInstances(ApplicationContextInitializer.class));
}

2.2 ApplicationListener 接口

ApplicationListener是一个接口,用于监听Spring框架中的各种事件。

2.2.1 定义
public interface ApplicationListener<E extends ApplicationEvent> extends EventListener {
    void onApplicationEvent(E event);
}
  • 功能:onApplicationEvent方法在事件发布时被调用,用于处理相应的事件。

2.2.2 使用

在SpringApplication的构造方法中,会加载所有ApplicationListener实现类:

public SpringApplication(Class<?>... primarySources) {
    this.setListeners((Collection) this.getSpringFactoriesInstances(ApplicationListener.class));
}

2.3 SpringApplicationRunListeners 类

SpringApplicationRunListeners类用于管理多个 SpringApplicationRunListener实例,并在不同的启动阶段调用它们。

2.3.1 定义

class SpringApplicationRunListeners {
    private final List<SpringApplicationRunListener> listeners;

    SpringApplicationRunListeners(Log logger, Collection<? extends SpringApplicationRunListener> listeners) {
        this.listeners = new ArrayList<>(listeners);
    }

    void starting() {
        for (SpringApplicationRunListener listener : this.listeners) {
            listener.starting();
        }
    }

    void environmentPrepared(ConfigurableEnvironment environment) {
        for (SpringApplicationRunListener listener : this.listeners) {
            listener.environmentPrepared(environment);
        }
    }

    void contextPrepared(ConfigurableApplicationContext context) {
        for (SpringApplicationRunListener listener : this.listeners) {
            listener.contextPrepared(context);
        }
    }

    void contextLoaded(ConfigurableApplicationContext context) {
        for (SpringApplicationRunListener listener : this.listeners) {
            listener.contextLoaded(context);
        }
    }

    void started(ConfigurableApplicationContext context) {
        for (SpringApplicationRunListener listener : this.listeners) {
            listener.started(context);
        }
    }

    void running(ConfigurableApplicationContext context) {
        for (SpringApplicationRunListener listener : this.listeners) {
            listener.running(context);
        }
    }

    void failed(ConfigurableApplicationContext context, Throwable exception) {
        for (SpringApplicationRunListener listener : this.listeners) {
            listener.failed(context, exception);
        }
    }
}
  • 功能:在应用程序启动的不同阶段,调用所有注册的 SpringApplicationRunListener 实例。

3. 关键子组件的具体实现

3.1 DefaultApplicationArguments 类

DefaultApplicationArguments类实现了ApplicationArguments接口,解析和封装传递给应用程序的命令行参数。

3.1.1 定义

public class DefaultApplicationArguments implements ApplicationArguments {
    private final Source source;

    public DefaultApplicationArguments(String[] args) {
        this.source = new Source(args);
    }

    @Override
    public String[] getSourceArgs() {
        return this.source.getSourceArgs();
    }

    @Override
    public Set<String> getOptionNames() {
        return this.source.getOptionNames();
    }

    @Override
    public boolean containsOption(String name) {
        return this.source.containsOption(name);
    }

    @Override
    public List<String> getOptionValues(String name) {
        return this.source.getOptionValues(name);
    }

    @Override
    public List<String> getNonOptionArgs() {
        return this.source.getNonOptionArgs();
    }
}
  • 功能:解析和封装命令行参数,提供便捷的参数访问方法。

3.2 Banner 类

Banner接口用于在应用程序启动时显示横幅信息。

3.2.1 定义
@FunctionalInterface
public interface Banner {
    void printBanner(Environment environment, Class<?> sourceClass, PrintStream out);

    Banner DEFAULT = new SpringBootBanner();
}
  • 功能:printBanner方法用于打印横幅信息,SpringBoot提供了默认实现 SpringBootBanner。

3.2.2 使用

在SpringApplication的run方法中,调用printBanner方法显示横幅信息:

Banner printedBanner = this.printBanner(environment);

4. 启动流程的细节分析(续)

4.1 prepareContext 方法

prepareContext 方法用于配置应用上下文。

private void prepareContext(ConfigurableApplicationContext context, ConfigurableEnvironment environment,
                            SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments, 
                            Banner printedBanner) {
    context.setEnvironment(environment);
    this.postProcessApplicationContext(context);
    this.applyInitializers(context);
    listeners.contextPrepared(context);
    if (printedBanner != null) {
        context.getBeanFactory().registerSingleton("springBootBanner", printedBanner);
    }
}
  • 功能:设置环境,调用初始化器,注册横幅,通知监听器上下文已准备就绪。

4.2 applyInitializers 方法

applyInitializers方法用于调用所有ApplicationContextInitializer实例的 initialize方法。

@SuppressWarnings({ "rawtypes", "unchecked" })
protected void applyInitializers(ConfigurableApplicationContext context) {
    for (ApplicationContextInitializer initializer : getInitializers()) {
        initializer.initialize(context);
    }
}
  • 功能:遍历并调用所有 ApplicationContextInitializer 实例对上下文进行自定义初始化。

4.3 callRunners 方法

callRunners方法用于调用所有实现了CommandLineRunner和 ApplicationRunner接口的 Bean。

private void callRunners(ApplicationContext context, ApplicationArguments args) {
    List<Object> runners = new ArrayList<>();
    runners.addAll(context.getBeansOfType(CommandLineRunner.class).values());
    runners.addAll(context.getBeansOfType(ApplicationRunner.class).values());
    AnnotationAwareOrderComparator.sort(runners);
    for (Object runner : new LinkedHashSet<>(runners)) {
        if (runner instanceof ApplicationRunner) {
            callRunner((ApplicationRunner) runner, args);
        }
        if (runner instanceof CommandLineRunner) {
            callRunner((CommandLineRunner) runner, args);
        }
    }
}
  • 功能:获取所有实现CommandLineRunner和ApplicationRunner接口的 Bean 并按顺序调用。

5. 结论

通过详细分析SpringApplication类及其子组件,我们进一步理解了 SpringBoot启动过程的内部机制。这些组件在启动过程中的各个阶段发挥了关键作用,确保了应用程序的顺利启动和运行。在后续的文章中,我们将继续探索SpringBoot的其他重要特性和实现细节。

  • 12
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

missterzy

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值