您当前的位置:首页 >> 资讯 >  >> 正文
从 SpringApplication 认识 Spring 应用启动过程_每日热门
来源: 博客园      时间:2023-06-15 12:15:02
一、SpringApplication 是什么?

Spring 应用的启动类。


【资料图】

二、SpringApplication 执行了什么?

创建 ApplicationContext 实例

ApplicationContext 就是我们所说的容器实例。

注册 CommandLinePropertySource

CommandLinePropertySource 的作用是将命令行参数输出为 Spring 属性。

刷新 ApplicationContext

这一步骤包括诸多操作,并且会加载所有的单例 bean。

触发 CommandLineRunner bean

CommandLineRunner 是一个接口,它只有一个 run() 方法。

凡是实现了此接口的类,如果被加载进容器,就会执行其 run() 方法。

容器中可以包含多个实现 CommandLineRunner 的 bean,执行顺序可以遵从 Ordered 接口或者 @Order 注解设置。

三、bean 加载源

SpringApplication 有诸多 bean 加载源:

AnnotatedBeanDefinitionReader

顾名思义,注解 bean 定义读取。

XmlBeanDefinitionReader

xml 配置资源读取。

ClassPathBeanDefinitionScanner

classpath 路径扫描。

GroovyBeanDefinitionReader

... ...

四、SpringApplication 创建
public SpringApplication(ResourceLoader resourceLoader, Class... primarySources) {this.resourceLoader = resourceLoader;Assert.notNull(primarySources, "PrimarySources must not be null");this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));this.webApplicationType = WebApplicationType.deduceFromClasspath();this.bootstrapRegistryInitializers = new ArrayList<>(getSpringFactoriesInstances(BootstrapRegistryInitializer.class));setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));this.mainApplicationClass = deduceMainApplicationClass();}
1、resourceLoader

参数可以为 null,为 null 时,使用默认:

(this.resourceLoader != null) ? this.resourceLoader: new DefaultResourceLoader(null);
2、primarySources

主要的 bean 定义来源。

3、webApplicationType

web 应用类型判断:

NONE:应用不会以 web 应用运行,且不会启动内嵌 web 服务器。

SERVLET:基于 servlet web 应用,运行于内嵌 web 服务器。

REACTIVE:响应式 web 应用,运行于内嵌 web 服务器。

4、bootstrapRegistryInitializers

BootstrapRegistryInitializer:回调接口,用于 BootstrapRegistry 初始化。

BootstrapRegistry:对象注册器,作用期间为从应用启动,Environment 处理直到 ApplicationContext 完备。

5、setInitializers

ApplicationContextInitializer 列表设置。

ApplicationContextInitializer:回调接口,用于 Spring ConfigurableApplicationContext 初始化。

通常用于 web 应用 ApplicationContext 自定义初始化。如注册 property source、激活 profile 等。

6、setListeners

ApplicationListener 列表设置。

ApplicationListener:应用事件监听接口,基于标准的 EventListener 接口,观察者模式实现。

7、mainApplicationClass

main class

五、SpringApplication.run() 逻辑
public ConfigurableApplicationContext run(String... args) {long startTime = System.nanoTime();DefaultBootstrapContext bootstrapContext = createBootstrapContext();ConfigurableApplicationContext context = null;configureHeadlessProperty();SpringApplicationRunListeners listeners = getRunListeners(args);listeners.starting(bootstrapContext, this.mainApplicationClass);try {ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);ConfigurableEnvironment environment = prepareEnvironment(listeners, bootstrapContext, applicationArguments);configureIgnoreBeanInfo(environment);Banner printedBanner = printBanner(environment);context = createApplicationContext();context.setApplicationStartup(this.applicationStartup);prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);refreshContext(context);afterRefresh(context, applicationArguments);Duration timeTakenToStartup = Duration.ofNanos(System.nanoTime() - startTime);if (this.logStartupInfo) {new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), timeTakenToStartup);}listeners.started(context, timeTakenToStartup);callRunners(context, applicationArguments);}catch (Throwable ex) {handleRunFailure(context, ex, listeners);throw new IllegalStateException(ex);}try {Duration timeTakenToReady = Duration.ofNanos(System.nanoTime() - startTime);listeners.ready(context, timeTakenToReady);}catch (Throwable ex) {handleRunFailure(context, ex, null);throw new IllegalStateException(ex);}return context;}

创建,刷新 ApplicationContext 并运行 Spring 应用。

1、startTime

使用 System.nanoTime(),计算耗时间隔更精确。不可用于获取具体时刻。

2、创建启动上下文

DefaultBootstrapContext = createBootstrapContext();

BootstrapContext:启动上下文,生命周期同 BootstrapRegistry。

DefaultBootstrapContext 继承了 BootstrapContext、BootstrapRegistry。

用于 BootstrapRegistry 初始化。

3、ConfigurableApplicationContext

可配置的 ApplicationContext。

4、获取事件监听器

SpringApplicationRunListeners = getRunListeners()。

Spring 应用运行期间事件监听。

5、starting 事件

listeners.starting():starting step。

6、启动参数处理

ApplicationArguments:提供 SpringApplication 启动参数访问。

7、应用环境配置

ConfigurableEnvironment = prepareEnvironment()

private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners,DefaultBootstrapContext bootstrapContext, ApplicationArguments applicationArguments) {// Create and configure the environmentConfigurableEnvironment environment = getOrCreateEnvironment();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.");bindToSpringApplication(environment);if (!this.isCustomEnvironment) {EnvironmentConverter environmentConverter = new EnvironmentConverter(getClassLoader());environment = environmentConverter.convertEnvironmentIfNecessary(environment, deduceEnvironmentClass());}ConfigurationPropertySources.attach(environment);return environment;}

configureEnvironment() 模板方法,代理执行 configurePropertySources() 及 configureProfiles() 方法。

configurePropertySources():PropertySource 配置,用于添加、移除或者调序 PropertySource 资源。CommandLinePropertySource 在这一步处理。

configureProfiles():应用 profile 设置。

ConfigurationPropertySources.attach(environment)

ConfigurationPropertySources:提供对 ConfigurationPropertySource 的访问。

attach(environment):就是将这个功能提供给 environment。

listeners.environmentPrepared(bootstrapContext, environment)

environment-prepared step。

DefaultPropertiesPropertySource.moveToEnd(environment)

DefaultPropertiesPropertySource:是一个 MapPropertySource,包含 SpringApplication 可以使用的一些默认属性。为了使用方便,默认会置于尾序。

bindToSpringApplication(environment)

将 environment 绑定到 SpringApplication。

Binder:用于对象绑定的容器。

8、configureIgnoreBeanInfo()9、打印 Banner

printBanner()。

10、创建 ApplicationContext

createApplicationContext()。

内部通过 ApplicationContextFactory 创建。

ApplicationContextFactory:策略接口,默认实现为 DefaultApplicationContextFactory。

11、ApplicationStartup 设置

为容器设置 ApplicationStartup,用于记录启动过程性能指标。

12、ApplicationContext 准备

prepareContext()

private void prepareContext(DefaultBootstrapContext bootstrapContext, ConfigurableApplicationContext context,ConfigurableEnvironment environment, SpringApplicationRunListeners listeners,ApplicationArguments applicationArguments, Banner printedBanner) {context.setEnvironment(environment);postProcessApplicationContext(context);applyInitializers(context);listeners.contextPrepared(context);bootstrapContext.close(context);if (this.logStartupInfo) {logStartupInfo(context.getParent() == null);logStartupProfileInfo(context);}// Add boot specific singleton beansConfigurableListableBeanFactory beanFactory = context.getBeanFactory();beanFactory.registerSingleton("springApplicationArguments", applicationArguments);if (printedBanner != null) {beanFactory.registerSingleton("springBootBanner", printedBanner);}if (beanFactory instanceof AbstractAutowireCapableBeanFactory) {((AbstractAutowireCapableBeanFactory) beanFactory).setAllowCircularReferences(this.allowCircularReferences);if (beanFactory instanceof DefaultListableBeanFactory) {((DefaultListableBeanFactory) beanFactory).setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);}}if (this.lazyInitialization) {context.addBeanFactoryPostProcessor(new LazyInitializationBeanFactoryPostProcessor());}context.addBeanFactoryPostProcessor(new PropertySourceOrderingBeanFactoryPostProcessor(context));// Load the sourcesSet sources = getAllSources();Assert.notEmpty(sources, "Sources must not be empty");load(context, sources.toArray(new Object[0]));listeners.contextLoaded(context);}

设置环境

postProcessApplicationContext() 前置处理

beanNameGenerator 设置,用于 bean 名称生成。

resourceLoader 设置,用于资源加载。

addConversionService:ConversionService 类型转换 Service。

applyInitializers()

ApplicationContextInitializer 应用

contextPrepared 事件

【spring.boot.application.context-prepared】step

BootstrapContext 关闭

注册 springApplicationArguments bean

注册 springBootBanner bean

AbstractAutowireCapableBeanFactory

设置是否允许 bean 之间的循环依赖,并自动处理,默认为 true。

设置是否允许 bean 定义覆盖,默认为 true。

lazyInitialization 懒加载

设置 LazyInitializationBeanFactoryPostProcessor post-processor。

PropertySource 重排序

设置 PropertySourceOrderingBeanFactoryPostProcessor post-processor。

getAllSources() bean 定义源加载

load() bean 定义加载,BeanDefinitionLoader

用于从底层资源加载 bean 定义信息,包括 xml、JavaConfig。

是基于 AnnotatedBeanDefinitionReader、XmlBeanDefinitionReader、ClassPathBeanDefinitionScanner 的门面模式。

beanNameGenerator、resourceLoader、environment 设置。

资源加载:

private void load(Object source) {  Assert.notNull(source, "Source must not be null");  if (source instanceof Class) {  load((Class) source);  return;  }  if (source instanceof Resource) {  load((Resource) source);  return;  }  if (source instanceof Package) {  load((Package) source);  return;  }  if (source instanceof CharSequence) {  load((CharSequence) source);  return;  }  throw new IllegalArgumentException("Invalid source type " + source.getClass());  }

contextLoaded() contextLoaded 事件

【spring.boot.application.context-loaded】step。

13、ApplicationContext 刷新

refreshContext()

注册 shutdownHook。

Runtime.getRuntime().addShutdownHook(new Thread(this, "SpringApplicationShutdownHook"));

刷新操作:加载或刷新

AbstractApplicationContext::refresh()public void refresh() throws BeansException, IllegalStateException {synchronized (this.startupShutdownMonitor) {StartupStep contextRefresh = this.applicationStartup.start("spring.context.refresh");// Prepare this context for refreshing.prepareRefresh();// Tell the subclass to refresh the internal bean factory.ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();// Prepare the bean factory for use in this context.prepareBeanFactory(beanFactory);try {// Allows post-processing of the bean factory in context subclasses.postProcessBeanFactory(beanFactory);StartupStep beanPostProcess = this.applicationStartup.start("spring.context.beans.post-process");// Invoke factory processors registered as beans in the context.invokeBeanFactoryPostProcessors(beanFactory);// Register bean processors that intercept bean creation.registerBeanPostProcessors(beanFactory);beanPostProcess.end();// Initialize message source for this context.initMessageSource();// Initialize event multicaster for this context.initApplicationEventMulticaster();// Initialize other special beans in specific context subclasses.onRefresh();// Check for listener beans and register them.registerListeners();// Instantiate all remaining (non-lazy-init) singletons.finishBeanFactoryInitialization(beanFactory);// Last step: publish corresponding event.finishRefresh();}catch (BeansException ex) {if (logger.isWarnEnabled()) {logger.warn("Exception encountered during context initialization - " +"cancelling refresh attempt: " + ex);}// Destroy already created singletons to avoid dangling resources.destroyBeans();// Reset "active" flag.cancelRefresh(ex);// Propagate exception to caller.throw ex;}finally {// Reset common introspection caches in Spring"s core, since we// might not ever need metadata for singleton beans anymore...resetCommonCaches();contextRefresh.end();}}}

作为启动方法,如果失败,则必须销毁所有已创建的单例bean。

StartupStep【spring.context.refresh】

准备刷新 prepareRefresh()

设置启动日期。

设置 active 标志。

initPropertySources():子类实现 PropertySource 初始化。

validateRequiredProperties():校验 ConfigurablePropertyResolver#setRequiredProperties 设置的必需属性。

obtainFreshBeanFactory():通过子类获取最新的内部 bean factory。如果存在旧的则先销毁,然后再创建新的返回。

prepareBeanFactory() 准备 bean factory

setBeanClassLoader():默认为线程上下文类加载器,用于 bean 定义加载。

setBeanExpressionResolver() spel 表达式解析设置:StandardBeanExpressionResolver。

addPropertyEditorRegistrar():ResourceEditorRegistrar 用于 bean 创建过程。

添加 ApplicationContextAwareProcessor post-processor。

注册依赖:BeanFactory、ResourceLoader、ApplicationEventPublisher、ApplicationContext。

添加 ApplicationListenerDetector post-processor:用于检测发现实现了 ApplicationListener 的 bean。

LoadTimeWeaver 处理。

environment、systemProperties、systemEnvironment、applicationStartup 注册。

postProcessBeanFactory():用于子类实现,修改内部 bean factory。

这一时期,所有的 bean 定义都已被加载,但还未实例化。

StartupStep【spring.context.beans.post-process】

invokeBeanFactoryPostProcessors() 触发所有已注册的 BeanFactoryPostProcessor

registerBeanPostProcessors() 注册 bean post-processor

StartupStep【spring.context.beans.post-process】 结束

initMessageSource() MessageSource 初始化

容器内 bean 名称:messageSource。

存在则检查并设置 ParentMessageSource。

不存在则创建默认 DelegatingMessageSource,设置 ParentMessageSource 并注册。

initApplicationEventMulticaster() 事件分发初始化

容器 bean:applicationEventMulticaster。ApplicationEventMulticaster 接口,用于管理 ApplicationListener,并执行事件分发。

不存在则创建并注册 SimpleApplicationEventMulticaster 对象。

onRefresh()

用于子类初始化一些特有的 bean。

模板方法,用于重写实现刷新逻辑。

registerListeners() 监听器注册

将实现了 ApplicationListener 接口的 bean 注册到容器。

finishBeanFactoryInitialization() 实例化所有余下的单例 bean。

conversionService。

注册内嵌值(${...})解析器。

初始化 LoadTimeWeaverAware。

停用类型匹配 ClassLoader。

freezeConfiguration() 冻结所有的 bean 定义。所有注册的 bean 定义都不允许再有变更。

preInstantiateSingletons() 实例化所有余下的单例 bean。

14、afterRefresh()

ApplicationContext 刷新完毕后调用。

15、StartupInfoLogger

记录应用启动信息。

16、started 事件

listeners.started()

17、Runner 调用

包括 ApplicationRunner 和 CommandLineRunner。

18 ready 事件

listeners.ready()

标签:

X 关闭

X 关闭

供应