关于c++:SpringBoot-之启动流程

35次阅读

共计 5359 个字符,预计需要花费 14 分钟才能阅读完成。

SpringBoot 是一个基于 Spring 框架的疾速开发框架,旨在简化 Spring 应用程序的开发和部署。在本文中,咱们将深入分析 SpringBoot 启动过程的源代码,并提供必要的解释和阐明。
SpringBoot 启动过程简介
SpringBoot 应用程序的启动过程能够分为以下几个步骤:

加载应用程序上下文
扫描应用程序中的所有组件
主动配置应用程序环境
启动嵌入式 Web 服务器

在上面的章节中,咱们将逐个剖析这些步骤的源代码。
加载应用程序上下文
SpringBoot 应用程序的上下文是一个蕴含所有应用程序组件的容器。在启动过程中,SpringBoot 会加载并初始化这个容器。
这个步骤的源代码在 SpringApplication 类中。具体来说,SpringApplication 类的 run 办法是这个过程的入口点。在这个办法中,Spring Boot 会通过调用 createApplicationContext 办法来创立应用程序上下文。
上面是 createApplicationContext 办法的源代码:
protected ConfigurableApplicationContext createApplicationContext() {

Class<?> contextClass = this.applicationContextClass;
if (contextClass == null) {
    try {switch (this.webApplicationType) {
            case SERVLET:
                contextClass = Class.forName(DEFAULT_SERVLET_WEB_CONTEXT_CLASS);
                break;
            case REACTIVE:
                contextClass = Class.forName(DEFAULT_REACTIVE_WEB_CONTEXT_CLASS);
                break;
            default:
                contextClass = Class.forName(DEFAULT_CONTEXT_CLASS);
        }
    }
    catch (ClassNotFoundException ex) {
        throw new IllegalStateException(
                "Unable to create a default ApplicationContext," +
                "please specify an ApplicationContextClass", ex);
    }
}
return (ConfigurableApplicationContext) BeanUtils.instantiateClass(contextClass);

}
复制代码
在这个办法中,SpringBoot 会依据应用程序类型(Servlet 或 Reactive)抉择适合的上下文类。而后,它会应用 Java 反射机制来实例化这个类并返回一个可配置的应用程序上下文对象。
扫描应用程序中的所有组件
在上一步中,SpringBoot 创立了应用程序上下文。在这一步中,SpringBoot 会扫描应用程序中的所有组件并将它们注册到应用程序上下文中。
这个步骤的源代码在 SpringApplication 类中的 scan 办法中。具体来说,在这个办法中,SpringBoot 会创立一个 SpringBootBeanDefinitionScanner 对象,并应用它来扫描应用程序中的所有组件。
上面是 scan 办法的源代码:
private void scan(String… basePackages) {

if (ObjectUtils.isEmpty(basePackages)) {return;}
ClassPathScanningCandidateComponentProvider scanner = new ClassPathScanningCandidateComponentProvider(this.includeFilters, this.excludeFilters, this.resourceLoader);
scanner.setResourceLoader(this.resourceLoader);
scanner.setEnvironment(this.environment);
scanner.setIncludeAnnotationConfig(this.useAnnotatedConfig);
scanner.addExcludeFilter(new AbstractTypeHierarchyTraversingFilter(false, false) {
    @Override
    protected boolean matchClassName(String className) {return getExcludeClassNames().contains(className);
    }
});
for (String basePackage : basePackages) {scanner.findCandidateComponents(basePackage).forEach(this.componentDefinitions::add);
}

}
复制代码
在这个办法中,SpringBoot 会创立一个 ClassPathScanningCandidateComponentProvider 对象,并应用它来扫描应用程序中的所有组件。这个对象会扫描指定包门路下的所有类,并将它们转换为 Spring 的 Bean 定义。这些 Bean 定义将被注册到应用程序上下文中。
主动配置应用程序环境
在上一步中,SpringBoot 将应用程序中的所有组件注册到应用程序上下文中。在这一步中,SpringBoot 将主动配置应用程序环境,包含配置数据源、事务管理器、JPA 等。
这个步骤的源代码在 SpringApplication 类中的 configureEnvironment 办法中。在这个办法中,Spring Boot 会创立一个 SpringApplicationRunListeners 对象,并应用它来配置应用程序环境。
上面是 configureEnvironment 办法的源代码:
private void configureEnvironment(ConfigurableEnvironment environment, String[] args) {

if (this.addCommandLineProperties) {ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
    environment.getPropertySources().addLast(new CommandLinePropertySource(applicationArguments));
}
this.listeners.environmentPrepared(environment);
if (this.logStartupInfo) {this.logStartupInfo(environment);
}
ConfigurationPropertySources.attach(environment);
Binder.get(environment).bind(ConfigurationPropertyName.EMPTY, Bindable.ofInstance(this.sources));
if (!this.isCustomEnvironment) {EnvironmentConverter.configureEnvironment(environment, this.deduceEnvironmentClass());
}
this.listeners.environmentPrepared(environment);

}
复制代码
在这个办法中,SpringBoot 会创立一个 ApplicationArguments 对象,并将其转换为一个命令行属性源。而后,它会调用 listeners 中的 environmentPrepared 办法来告诉应用程序环境曾经筹备好了。随后,SpringBoot 会绑定属性源到应用程序环境中,并调用 listeners 中的 environmentPrepared 办法来告诉应用程序环境曾经筹备好了。
启动嵌入式 Web 服务器
在上一步中,SpringBoot 将应用程序环境主动配置实现。在这一步中,SpringBoot 将启动嵌入式 Web 服务器,以便应用程序可能提供 Web 服务。
这个步骤的源代码在 SpringApplication 类中的 run 办法中。具体来说,在这个办法中,SpringBoot 会依据应用程序类型(Servlet 或 Reactive)抉择适合的嵌入式 Web 服务器,并应用它来启动应用程序。
上面是 run 办法的源代码:
public ConfigurableApplicationContext run(String… args) {

StopWatch stopWatch = new StopWatch();
stopWatch.start();
ConfigurableApplicationContext context = null;
Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
configureHeadlessProperty();
SpringApplicationRunListeners listeners = getRunListeners(args);
listeners.starting();
try {ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
    ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);
    configureIgnoreBeanInfo(environment);
    Banner printedBanner = printBanner(environment);
    context = createApplicationContext();
    exceptionReporters = getSpringFactoriesInstances(
            SpringBootExceptionReporter.class,
            new Class[] { ConfigurableApplicationContext.class}, context);
    prepareContext(context, environment, listeners, applicationArguments, printedBanner);
    refreshContext(context);
    afterRefresh(context, applicationArguments);
    stopWatch.stop();
    if (this.logStartupInfo) {new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch);
    }
    listeners.started(context);
    callRunners(context, applicationArguments);
}
catch (Throwable ex) {handleRunFailure(context, ex, exceptionReporters, listeners);
    throw new IllegalStateException(ex);
}
try {listeners.running(context);
}
catch (Throwable ex) {handleRunFailure(context, ex, exceptionReporters, null);
    throw new IllegalStateException(ex);
}
return context;

}
复制代码
在这个办法中,SpringBoot 会应用一个 StopWatch 对象来计算应用程序启动工夫。而后,它会调用 listeners 中的 starting 办法来告诉应用程序行将启动。接着,SpringBoot 会筹备应用程序环境,并应用它来创立应用程序上下文。随后,SpringBoot 会调用 listeners 中的 started 办法来告诉应用程序曾经启动。最初,SpringBoot 会调用 callRunners 办法来运行所有的 CommandLineRunner 和 ApplicationRunner 组件。
总结
在本文中,咱们深入分析了 SpringBoot 应用程序的启动过程的源代码。咱们理解了 SpringBoot 如何加载应用程序上下文、扫描应用程序中的所有组件、主动配置应用程序环境以及启动嵌入式 Web 服务器。这些步骤的源代码展现了 SpringBoot 如何简化应用程序的开发和部署。

正文完
 0