SpringBoot启动流程简析(二)

简介: 在这篇文章中,我们接着上一篇的内容接着分析。 public ConfigurableApplicationContext run(String.

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

    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类图。

相关文章
|
4月前
|
前端开发 Java 应用服务中间件
SpringBoot-Run启动流程
探索Spring Boot启动流程,从加载配置、创建应用上下文、自动配置到启动内嵌服务器。启动类是入口点,`@SpringBootApplication`标记启动,`SpringApplication.run`启动应用。自动配置基于条件注解配置Bean,应用上下文由`SpringApplication`创建并刷新。内嵌服务器如Tomcat随应用启动,简化部署。理解此流程有助于深入掌握Spring Boot。
202 2
|
4月前
|
缓存 Java 程序员
springboot的启动流程总结
springboot的启动流程总结
|
4月前
|
设计模式 Java 容器
SpringBoot2 | SpringBoot启动流程源码分析(二)
SpringBoot2 | SpringBoot启动流程源码分析(二)
73 0
|
4月前
|
设计模式 Java 机器人
SpringBoot3自动配置流程 SPI机制 核心注解 自定义starter
SpringBoot3自动配置流程 SPI机制 核心注解 自定义starter
|
3月前
|
JavaScript Java 测试技术
基于springboot+vue.js+uniapp小程序的销售项目流程化管理系统附带文章源码部署视频讲解等
基于springboot+vue.js+uniapp小程序的销售项目流程化管理系统附带文章源码部署视频讲解等
57 3
|
1月前
|
XML Java 应用服务中间件
SpringBoot启动流程解析
SpringBoot启动流程解析
29 0
|
2月前
|
Java 持续交付 Maven
Spring Boot程序的打包与运行:构建高效部署流程
构建高效的Spring Boot部署流程对于保障应用的快速、稳定上线至关重要。通过采用上述策略,您可以确保部署过程的自动化、可靠性和高效性,从而将专注点放在开发上面。无论是通过Maven的生命周期命令进行打包,还是通过容器技术对部署过程进行优化,选择正确的工具与实践是成功实现这一目标的关键。
109 2
|
4月前
|
安全 NoSQL Java
SpringBoot集成Activiti5.22在线流程设计器
SpringBoot集成Activiti5.22在线流程设计器
170 0
SpringBoot集成Activiti5.22在线流程设计器
|
4月前
|
JavaScript Java 测试技术
基于SpringBoot+Vue+uniapp微信小程序的工作流程管理系统的详细设计和实现
基于SpringBoot+Vue+uniapp微信小程序的工作流程管理系统的详细设计和实现
|
4月前
|
Java Spring 容器
深入理解Spring Boot启动流程及其实战应用
【5月更文挑战第9天】本文详细解析了Spring Boot启动流程的概念和关键步骤,并结合实战示例,展示了如何在实际开发中运用这些知识。
131 2