赞
踩
Spring Boot是一个基于Spring框架的快速开发工具,它可以帮助我们快速搭建一个可运行的Spring应用。本文将详细介绍Spring Boot的启动流程,帮助大家更好地理解Spring Boot的工作原理。
Spring Boot的启动流程可以分为以下几个阶段:
初始化配置
创建应用程序上下文
刷新上下文(启动核心)
通知监听者-启动程序完成
public ConfigurableApplicationContext run(String... args) { long startTime = System.nanoTime(); DefaultBootstrapContext bootstrapContext = this.createBootstrapContext(); ConfigurableApplicationContext context = null; this.configureHeadlessProperty(); SpringApplicationRunListeners listeners = this.getRunListeners(args); listeners.starting(bootstrapContext, this.mainApplicationClass); try { // 获取args参数对象 ApplicationArguments applicationArguments = new DefaultApplicationArguments(args); // 读取Springboot配置文件并创建Environment对象 // 这里创建的Environment对象实际为ConfigurableEnvironment ConfigurableEnvironment environment = this.prepareEnvironment(listeners, bootstrapContext, applicationArguments); this.configureIgnoreBeanInfo(environment); // 打印Banner图标 Banner printedBanner = this.printBanner(environment); // 创建ApplicationContext应用行下文,即创建容器 context = this.createApplicationContext(); context.setApplicationStartup(this.applicationStartup); // 准备容器 this.prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner); // 初始化容器 this.refreshContext(context); this.afterRefresh(context, applicationArguments); Duration timeTakenToStartup = Duration.ofNanos(System.nanoTime() - startTime); if (this.logStartupInfo) { (new StartupInfoLogger(this.mainApplicationClass)).logStarted(this.getApplicationLog(), timeTakenToStartup); } // 调用运行时监听器的started()方法 // 该方法需要在应用程序启动后,CommandLineRunners和ApplicationRunners被调用前执行 listeners.started(context, timeTakenToStartup); this.callRunners(context, applicationArguments); } catch (Throwable var12) { this.handleRunFailure(context, var12, listeners); throw new IllegalStateException(var12); } try { Duration timeTakenToReady = Duration.ofNanos(System.nanoTime() - startTime); listeners.ready(context, timeTakenToReady); return context; } catch (Throwable var11) { this.handleRunFailure(context, var11, (SpringApplicationRunListeners)null); throw new IllegalStateException(var11); } }
这段代码是Spring Boot启动时的核心方法,它的主要作用是创建和配置Spring应用程序的上下文。
首先,记录启动开始时间,并创建一个DefaultBootstrapContext对象和一个空的ConfigurableApplicationContext对象。然后,获取运行监听器并调用其starting()方法,表示应用程序正在启动。
接下来,创建一个ApplicationArguments对象,用于存储应用程序的命令行参数。然后,调用prepareEnvironment()方法准备环境,包括加载配置文件、扫描并注册Bean、初始化Spring容器等。
接着,打印应用程序的Banner信息,并创建一个新的ConfigurableApplicationContext对象。设置应用程序的启动类和启动配置,并调用prepareContext()方法准备上下文。
然后,调用refreshContext()方法刷新上下文,并调用afterRefresh()方法执行一些后续操作。计算应用程序启动所花费的时间,并在日志中记录启动信息。
最后,调用运行监听器的started()方法,表示应用程序已经启动。然后,调用callRunners()方法执行所有的CommandLineRunner和ApplicationRunner接口实现。
如果在启动过程中出现异常,会调用handleRunFailure()方法处理异常,并抛出一个IllegalStateException异常。
最后,调用运行监听器的ready()方法,表示应用程序已经准备好,并返回创建的ConfigurableApplicationContext对象。
Spring Boot启动时,会首先加载配置文件(如application.properties或application.yml)中的配置信息。这些配置信息包括数据源、缓存、日志等相关信息。
private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners, DefaultBootstrapContext bootstrapContext, ApplicationArguments applicationArguments) { ConfigurableEnvironment environment = this.getOrCreateEnvironment(); this.configureEnvironment(environment, applicationArguments.getSourceArgs()); ConfigurationPropertySources.attach(environment); listeners.environmentPrepared(bootstrapContext, environment); DefaultPropertiesPropertySource.moveToEnd(environment); Assert.state(!environment.containsProperty("spring.main.environment-prefix"), "Environment prefix cannot be set via properties."); this.bindToSpringApplication(environment); if (!this.isCustomEnvironment) { EnvironmentConverter environmentConverter = new EnvironmentConverter(this.getClassLoader()); environment = environmentConverter.convertEnvironmentIfNecessary(environment, this.deduceEnvironmentClass()); } ConfigurationPropertySources.attach(environment); return environment; }
这段代码是一个名为prepareEnvironment的方法,它接收三个参数:listeners(SpringApplicationRunListeners类型)、bootstrapContext(DefaultBootstrapContext类型)和applicationArguments(ApplicationArguments类型)。该方法的主要作用是准备和配置Spring应用程序的环境。
首先,通过调用this.getOrCreateEnvironment()方法获取或创建一个ConfigurableEnvironment对象,并将其赋值给变量environment。
接下来,调用this.configureEnvironment(environment, applicationArguments.getSourceArgs())方法对环境进行配置,传入environment和applicationArguments.getSourceArgs()作为参数。
然后,调用ConfigurationPropertySources.attach(environment)方法将环境附加到配置属性源。
接着,调用listeners.environmentPrepared(bootstrapContext, environment)方法通知监听器环境已准备好。
然后,调用DefaultPropertiesPropertySource.moveToEnd(environment)方法将默认属性源移动到环境的末尾。
接下来,使用断言语句Assert.state(!environment.containsProperty(“spring.main.environment-prefix”), “Environment prefix cannot be set via properties.”)确保环境中不包含名为"spring.main.environment-prefix"的属性。
然后,调用this.bindToSpringApplication(environment)方法将环境绑定到Spring应用程序。
如果this.isCustomEnvironment为false,则创建一个EnvironmentConverter对象,并调用其convertEnvironmentIfNecessary(environment, this.deduceEnvironmentClass())方法根据需要转换环境。
最后,再次调用ConfigurationPropertySources.attach(environment)方法将环境附加到配置属性源,并将environment返回。
初始化和配置好后,开始创建应用程序上下文,createApplicationContext ,关键的工厂BeanFactory就是此处创建
protected ConfigurableApplicationContext createApplicationContext() {
return this.applicationContextFactory.create(this.webApplicationType);
}
工厂配置,bean处理器配置,类的扫描,解析,bean定义,bean类信息缓存,服务器创建,bean实例化,动态代理对象的创建等,
private void refreshContext(ConfigurableApplicationContext context) {
if (this.registerShutdownHook) {
shutdownHook.registerApplicationContext(context);
}
this.refresh(context);
}
该方法的主要作用是刷新Spring应用程序的上下文。
首先,如果this.registerShutdownHook为true,则调用shutdownHook.registerApplicationContext(context)方法将应用程序上下文注册到关闭钩子中。
然后,调用this.refresh(context)方法刷新上下文。
public void refresh() throws BeansException, IllegalStateException { synchronized(this.startupShutdownMonitor) { StartupStep contextRefresh = this.applicationStartup.start("spring.context.refresh"); this.prepareRefresh(); ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory(); this.prepareBeanFactory(beanFactory); try { this.postProcessBeanFactory(beanFactory); StartupStep beanPostProcess = this.applicationStartup.start("spring.context.beans.post-process"); //注册并实例化bean工厂处理器,并调用他们 this.invokeBeanFactoryPostProcessors(beanFactory); //注册并实例化bean处理器 this.registerBeanPostProcessors(beanFactory); beanPostProcess.end(); this.initMessageSource(); this.initApplicationEventMulticaster(); //初始化一些与上下文有特别关系的bean对象(创建tomcat) this.onRefresh(); this.registerListeners(); // 实例化所有bean工厂缓存的bean对象(剩下的). this.finishBeanFactoryInitialization(beanFactory); //发布通知-通知上下文刷新完成(包括启动tomcat) this.finishRefresh(); } catch (BeansException var10) { if (this.logger.isWarnEnabled()) { this.logger.warn("Exception encountered during context initialization - cancelling refresh attempt: " + var10); } this.destroyBeans(); this.cancelRefresh(var10); throw var10; } finally { this.resetCommonCaches(); contextRefresh.end(); } } }
该方法的主要作用是刷新Spring应用程序的上下文。
首先,通过同步块来确保线程安全。然后,创建一个名为contextRefresh的StartupStep对象,并调用this.prepareRefresh()方法准备刷新。接着,获取一个新的BeanFactory对象,并调用this.prepareBeanFactory(beanFactory)方法准备BeanFactory。
接下来,在try-catch语句中执行以下操作:
如果在执行过程中出现BeansException异常,会记录警告日志,销毁Beans,取消刷新操作,并抛出该异常。最后,在finally语句中重置缓存和计时器。
发布通知监听器启动完成,监听器会根据事件类型做个性化操作
void starting(ConfigurableBootstrapContext bootstrapContext, Class<?> mainApplicationClass) { this.doWithListeners("spring.boot.application.starting", (listener) -> { listener.starting(bootstrapContext); }, (step) -> { if (mainApplicationClass != null) { step.tag("mainApplicationClass", mainApplicationClass.getName()); } }); } void environmentPrepared(ConfigurableBootstrapContext bootstrapContext, ConfigurableEnvironment environment) { this.doWithListeners("spring.boot.application.environment-prepared", (listener) -> { listener.environmentPrepared(bootstrapContext, environment); }); } void contextPrepared(ConfigurableApplicationContext context) { this.doWithListeners("spring.boot.application.context-prepared", (listener) -> { listener.contextPrepared(context); }); } void contextLoaded(ConfigurableApplicationContext context) { this.doWithListeners("spring.boot.application.context-loaded", (listener) -> { listener.contextLoaded(context); }); } void started(ConfigurableApplicationContext context, Duration timeTaken) { this.doWithListeners("spring.boot.application.started", (listener) -> { listener.started(context, timeTaken); }); } void ready(ConfigurableApplicationContext context, Duration timeTaken) { this.doWithListeners("spring.boot.application.ready", (listener) -> { listener.ready(context, timeTaken); }); } void failed(ConfigurableApplicationContext context, Throwable exception) { this.doWithListeners("spring.boot.application.failed", (listener) -> { this.callFailedListener(listener, context, exception); }, (step) -> { step.tag("exception", exception.getClass().toString()); step.tag("message", exception.getMessage()); }); } private void callFailedListener(SpringApplicationRunListener listener, ConfigurableApplicationContext context, Throwable exception) { try { listener.failed(context, exception); } catch (Throwable var6) { if (exception == null) { ReflectionUtils.rethrowRuntimeException(var6); } if (this.log.isDebugEnabled()) { this.log.error("Error handling failed", var6); } else { String message = var6.getMessage(); message = message != null ? message : "no error message"; this.log.warn("Error handling failed (" + message + ")"); } } } private void doWithListeners(String stepName, Consumer<SpringApplicationRunListener> listenerAction) { this.doWithListeners(stepName, listenerAction, (Consumer)null); } private void doWithListeners(String stepName, Consumer<SpringApplicationRunListener> listenerAction, Consumer<StartupStep> stepAction) { StartupStep step = this.applicationStartup.start(stepName); this.listeners.forEach(listenerAction); if (stepAction != null) { stepAction.accept(step); } step.end(); }
SpringApplicationRunListeners是Spring Boot框架中的一个接口,用于监听应用程序的运行过程。它提供了一系列的回调方法,可以在应用程序的不同阶段执行自定义的逻辑。
以下是SpringApplicationRunListeners接口中定义的一些主要方法:
通过以上介绍,我们了解了Spring Boot的启动流程。Spring Boot通过自动化的配置和简化的部署流程,使得我们能够快速搭建一个可运行的Spring应用。希望本文能够帮助大家更好地理解Spring Boot的工作原理。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。