SpringBoot启动流程简析(二)

在这篇文章中,我们接着上一篇的内容接着分析。

    public ConfigurableApplicationContext run(String... args) {
        //启动应用的检测
        StopWatch stopWatch = new StopWatch();
        stopWatch.start();
        //SpringBoot的上下文
        ConfigurableApplicationContext context = null;
        //失败分析报告
        FailureAnalyzers analyzers = null;
        configureHeadlessProperty();
        //SpringBoot的runlistener
        SpringApplicationRunListeners listeners = getRunListeners(args);
        listeners.starting();
        try {
        //参数解析
            ApplicationArguments applicationArguments = new DefaultApplicationArguments(
                    args);
                    //配置环境变量
            ConfigurableEnvironment environment = prepareEnvironment(listeners,
                    applicationArguments);
            //输出Banner信息        
            Banner printedBanner = printBanner(environment);
            //创建应用上下文
            context = createApplicationContext();
            analyzers = new FailureAnalyzers(context);
            //refresh上下文之前的准备
            prepareContext(context, environment, listeners, applicationArguments,
                    printedBanner);
            refreshContext(context);
            afterRefresh(context, applicationArguments);
            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);
        }
    }

SpringApplication中的run方法的内容如上所示,上面就是整个SpringBoot应用启动的主要调用方法,run方法中的参数即是我们的应用参数。下面我们来简单的分析一下这个启动过程。
StopWatch主要是监控启动过程,统计启动时间,检测应用是否已经启动或者停止。

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

通过在上一篇文章中的问题,对于getSpringFactoriesInstances这个方法你应该不陌生来吧。这里也是从META-INF/spring.factories中获取类型为org.springframework.boot.SpringApplicationRunListener的配置值,这个默认的配置值为:org.springframework.boot.context.event.EventPublishingRunListener。我们进入到EventPublishingRunListener这个类看一下它的构造函数

    public EventPublishingRunListener(SpringApplication application, String[] args) {
        this.application = application;
        this.args = args;
        //创建一个SimpleApplicationEventMulticaster
        this.initialMulticaster = new SimpleApplicationEventMulticaster();
        //把之前在SpringApplication中获取到的listener循环放入到SimpleApplicationEventMulticaster中
        for (ApplicationListener<?> listener : application.getListeners()) {
    this.initialMulticaster.addApplicationListener(listener);
        }
    }

通过上面的分析,我们可以看到EventPublishingRunListener把SpringApplication中的监听器,都放到了SimpleApplicationEventMulticaster中,进行了统一的管理。listeners.starting();启动事件监听,这里以后我们单独开章节详细说明.

 //创建应用参数解析器
 ApplicationArguments applicationArguments = new DefaultApplicationArguments(
                    args);

我们看一下DefaultApplicationArguments的构造函数的内容:

    public DefaultApplicationArguments(String[] args) {
            //首先判断不能为null,这里大家可以想一下可变参数如果不传值的话看看是什么内容
        Assert.notNull(args, "Args must not be null");
        //调用Source对应用参数进行解析
        this.source = new Source(args);
        this.args = args;
    }
Source(String[] args) {
//调用父类的构造函数 Source的继承关系如下图所示
    super(args);
}
public SimpleCommandLinePropertySource(String... args) {
    //对应参数进行解析的工作
    super(new SimpleCommandLineArgsParser().parse(args));
}

Source
大家在配置应用参数的时候,是这样这样配置的 - -key=value,为什么要以- -开头呢?在SimpleCommandLineArgsParser的parse方法中你会找到答案。并且Source这个类还继承类PropertySource这个类。

//准备环境变量
ConfigurableEnvironment environment =           prepareEnvironment(listeners,applicationArguments); 
private ConfigurableEnvironment prepareEnvironment(
    SpringApplicationRunListeners listeners,
    ApplicationArguments applicationArguments) {
    //获取环境变量 
    ConfigurableEnvironment environment = getOrCreateEnvironment();
    //将应用参数放入到环境变量持有对象中
    configureEnvironment(environment, applicationArguments.getSourceArgs());
    //监听器监听环境变量对象的变化
    listeners.environmentPrepared(environment);
    //如果非web环境,则转换为StandardEnvironment对象
    if (!this.webEnvironment) {
        environment = new EnvironmentConverter(getClassLoader())            .convertToStandardEnvironmentIfNecessary(environment);
    }
    return environment;
}
    private ConfigurableEnvironment getOrCreateEnvironment() {
        //如果已经创建过存放环境变量的对象了,则直接返回
        if (this.environment != null) {
            return this.environment;
        }
        //如果是web环境则创建StandardServletEnvironment对象
        if (this.webEnvironment) {
            return new StandardServletEnvironment();
        }
        //非web环境,创建StandardEnvironment
        return new StandardEnvironment();
    }

StandardServletEnvironment的UML图如下所示,StandardServletEnvironment集成了系统变量、环境变量、配置属性信息等内容。这些内容我们以后单开一个篇章来说一下。
StandardServletEnvironment

//这句话是输出SpringBoot的Banner信息,可以从指定的位置加载信息,可以输出为文字形式,也可以输出为图片形式,如我们常见的SpringBoot的logo就是在这里输出的
Banner printedBanner = printBanner(environment);

SpringBootBanner
Banner的UML类图如下所示:
Banner
我们最常见的SpringBoot的logo“图像”就在SpringBootBanner这个类中定义的,这个也是SpringBoot默认的Banner类。
SpringBootBanner

//创建SpringBoot的应用上下文
context = createApplicationContext();
protected ConfigurableApplicationContext createApplicationContext() {
    Class<?> contextClass = this.applicationContextClass;
    if (contextClass == null) {
        try {
        //DEFAULT_WEB_CONTEXT_CLASS = org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext
        /// DEFAULT_CONTEXT_CLASS = org.springframework.context.annotation.AnnotationConfigApplicationContext
        contextClass = Class.forName(this.webEnvironment
                ? DEFAULT_WEB_CONTEXT_CLASS : DEFAULT_CONTEXT_CLASS);
        }
    }
    return (ConfigurableApplicationContext) BeanUtils.instantiate(contextClass);
}

因为我们是web开发环境,所以这里我们的web上下文是AnnotationConfigEmbeddedWebApplicationContext这个对象,一定要记住这个类,要仔细的看看它的UML类图。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值