网站推广.NET

网站推广.NET

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启动流程