文章目录
- [一、创建一个简单的 SpringBoot 项目](#一、创建一个简单的 SpringBoot 项目)
- [二、SpringApplication 的 run() 方法调用](#二、SpringApplication 的 run() 方法调用)
- [三、SpringApplication 的构造函数](#三、SpringApplication 的构造函数)
- 四、启动流程
一、创建一个简单的 SpringBoot 项目
java
package org.yoel.qyyboot;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
@SpringBootApplication
public class QyybootApplication {
public static void main(String[] args) {
ConfigurableApplicationContext run = SpringApplication.run(QyybootApplication.class, args);
Object myService = run.getBean("myService");
System.out.println("myService = " + myService);
}
}
二、SpringApplication 的 run() 方法调用
java
// 第一步
public static ConfigurableApplicationContext run(Class<?> primarySource, String... args) {
return run(new Class[]{primarySource}, args);
}
// 第二步
public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {
return (new SpringApplication(primarySources)).run(args);
}
// 第三步
public ConfigurableApplicationContext run(String... args) {
}
三、SpringApplication 的构造函数
java
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
// 初始化源集合(通常是主配置类)为空的有序集合
this.sources = new LinkedHashSet<>();
// 设置启动横幅模式为控制台输出
this.bannerMode = Mode.CONSOLE;
// 设置是否记录启动信息,默认为开启
this.logStartupInfo = true;
// 设置是否将命令行参数作为环境变量添加到上下文中,默认为开启
this.addCommandLineProperties = true;
// 设置是否自动注册类型转换服务,默认为开启
this.addConversionService = true;
// 设置是否以无头模式运行,默认为开启
this.headless = true;
// 设置是否注册关闭钩子,默认为开启
this.registerShutdownHook = true;
// 初始化额外的配置文件名集合为空集合
this.additionalProfiles = Collections.emptySet();
// 标记是否使用了自定义的环境配置,默认为否
this.isCustomEnvironment = false;
// 设置懒加载初始化标志,默认为不懒加载
this.lazyInitialization = false;
// 设置默认的应用上下文工厂
this.applicationContextFactory = ApplicationContextFactory.DEFAULT;
// 设置默认的应用启动行为
this.applicationStartup = ApplicationStartup.DEFAULT;
// 设置资源加载器
this.resourceLoader = resourceLoader;
// 验证主源配置类不能为空
Assert.notNull(primarySources, "PrimarySources must not be null");
// 将主源配置类存储到有序集合中
this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
// 初始化环境。环境分为三种 非web环境、web环境、reactive环境三种。其判断逻辑就是判断是否存在指定的类,默认是Servlet 环境,我们这也是Servlet
this.webApplicationType = WebApplicationType.deduceFromClasspath();
// 获取并存储所有 BootstrapRegistryInitializer 实例
this.bootstrapRegistryInitializers = new ArrayList<>(this.getSpringFactoriesInstances(BootstrapRegistryInitializer.class));
// getSpringFactoriesInstances 方法加载了 spring.factories文件。在这里进行了首次加载spring.factoies文件。设置 ApplicationContextInitializer
this.setInitializers(this.getSpringFactoriesInstances(ApplicationContextInitializer.class));
// 获取监听器,也加载了spring.factories文件
this.setListeners(this.getSpringFactoriesInstances(ApplicationListener.class));
// 推断主应用程序类
this.mainApplicationClass = this.deduceMainApplicationClass();
}
四、启动流程
java
public ConfigurableApplicationContext run(String... args) {
// 创建一个 SpringApplication 的 Startup 实例来跟踪启动过程
Startup startup = SpringApplication.Startup.create();
// 如果设置了注册关闭钩子,则允许添加关闭钩子
if (this.registerShutdownHook) {
shutdownHook.enableShutdownHookAddition();
}
// 创建 Bootstrap 上下文
DefaultBootstrapContext bootstrapContext = this.createBootstrapContext();
// 初始化上下文对象为 null,稍后会创建
ConfigurableApplicationContext context = null;
// 如果设置了无头模式,则配置相应的系统属性
this.configureHeadlessProperty();
// 创建并初始化 Run Listeners
SpringApplicationRunListeners listeners = this.getRunListeners(args);
// 在启动过程开始时通知 Run Listeners
listeners.starting(bootstrapContext, this.mainApplicationClass);
Throwable ex;
try {
// 解析命令行参数
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
// 准备环境配置
ConfigurableEnvironment environment = this.prepareEnvironment(listeners, bootstrapContext, applicationArguments);
// 输出横幅信息
Banner printedBanner = this.printBanner(environment);
// 创建应用上下文
context = this.createApplicationContext();
// 设置上下文启动策略
context.setApplicationStartup(this.applicationStartup);
// 准备上下文,包括初始化 BeanFactory、设置环境等
this.prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);
// 刷新上下文,完成 Bean 的初始化
this.refreshContext(context);
// 上下文刷新后的操作
this.afterRefresh(context, applicationArguments);
// 启动完成后调用 Startup 的 started 方法
startup.started();
// 如果设置了记录启动信息,则记录应用启动的日志
if (this.logStartupInfo) {
(new StartupInfoLogger(this.mainApplicationClass)).logStarted(this.getApplicationLog(), startup);
}
// 通知 Run Listeners 启动完成
listeners.started(context, startup.timeTakenToStarted());
// 执行任何定义好的 Runner 接口实现
this.callRunners(context, applicationArguments);
} catch (Throwable var10) {
// 捕获异常,用于处理启动失败的情况
ex = var10;
// 抛出处理后的异常
throw this.handleRunFailure(context, ex, listeners);
}
try {
// 如果上下文正在运行,则通知 Run Listeners 已经准备就绪
if (context.isRunning()) {
listeners.ready(context, startup.ready());
}
// 返回创建的上下文
return context;
} catch (Throwable var9) {
// 捕获异常,用于处理启动成功后可能出现的问题
ex = var9;
// 抛出处理后的异常
throw this.handleRunFailure(context, ex, (SpringApplicationRunListeners)null);
}
}
流程详解:
1、获取监听器
java
SpringApplicationRunListeners listeners = this.getRunListeners(args);
java
private SpringApplicationRunListeners getRunListeners(String[] args) {
// 创建一个 ArgumentResolver 实例,用于解析构造方法的参数
SpringFactoriesLoader.ArgumentResolver argumentResolver = ArgumentResolver.of(SpringApplication.class, this);
// 使用 ArgumentResolver 添加 String[] 类型的参数,即启动时传入的命令行参数
argumentResolver = argumentResolver.and(String[].class, args);
// 从 spring.factories 文件中获取 SpringApplicationRunListener 的所有实例
List<SpringApplicationRunListener> listeners = this.getSpringFactoriesInstances(SpringApplicationRunListener.class, argumentResolver);
// 获取当前的 SpringApplicationHook 实例
SpringApplicationHook hook = (SpringApplicationHook)applicationHook.get();
// 如果存在 SpringApplicationHook,则获取其提供的 SpringApplicationRunListener 实例
SpringApplicationRunListener hookListener = hook != null ? hook.getRunListener(this) : null;
// 如果 hook 提供了 SpringApplicationRunListener,则将其添加到监听器列表中
if (hookListener != null) {
listeners = new ArrayList<>(listeners);
((List)listeners).add(hookListener);
}
// 创建 SpringApplicationRunListeners 实例,并传递日志记录器、监听器列表和应用启动行为
return new SpringApplicationRunListeners(logger, (List)listeners, this.applicationStartup);
}
factories
# Run Listeners
org.springframework.boot.SpringApplicationRunListener=\
org.springframework.boot.context.event.EventPublishingRunListener
Spring启动时,通过 spring.factories 文件中获取监听器集合。默认类型为 EventPublishingRunListener。在事件发生时,EventPublishingRunListener 会寻找容器中 ApplicationListener 的bean,并进行事件通知。
2、加载环境配置
application.yml或者application.properties文件
java
ConfigurableEnvironment environment = this.prepareEnvironment(listeners, bootstrapContext, applicationArguments);
java
private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners, DefaultBootstrapContext bootstrapContext, ApplicationArguments applicationArguments) {
// 获取或创建 ConfigurableEnvironment 实例
ConfigurableEnvironment environment = this.getOrCreateEnvironment();
// 配置环境,主要是将命令行参数应用到环境中
this.configureEnvironment(environment, applicationArguments.getSourceArgs());
// 将配置属性源附加到环境
ConfigurationPropertySources.attach(environment);
// 通知 Run Listeners 环境已准备好
listeners.environmentPrepared(bootstrapContext, environment);
// 将默认属性移动到最后,确保它们不会覆盖其他来源的属性
DefaultPropertiesPropertySource.moveToEnd(environment);
// 断言环境前缀不能通过属性设置
Assert.state(!environment.containsProperty("spring.main.environment-prefix"), "Environment prefix cannot be set via properties.");
// 将 SpringApplication 的信息绑定到环境中
this.bindToSpringApplication(environment);
// 如果不是自定义的环境,则尝试转换环境
if (!this.isCustomEnvironment) {
// 创建 EnvironmentConverter 实例
EnvironmentConverter environmentConverter = new EnvironmentConverter(this.getClassLoader());
// 根据需要转换环境
environment = environmentConverter.convertEnvironmentIfNecessary(environment, this.deduceEnvironmentClass());
}
// 再次将配置属性源附加到环境中
ConfigurationPropertySources.attach(environment);
// 返回准备好的环境
return environment;
}
在 listeners.environmentPrepared(environment); 时会发送环境准备事件,环境准备事件要通知七个监听器。对于 Springboot 的配置文件application.yml或者application.properties文件的加载实际上是通过发布环境准备事件完成的,完成这项功能的就是 EnvironmentPostProcessorApplicationListener
factories
# Application Listeners
org.springframework.context.ApplicationListener=\
org.springframework.boot.ClearCachesApplicationListener,\
org.springframework.boot.builder.ParentContextCloserApplicationListener,\
org.springframework.boot.context.FileEncodingApplicationListener,\
org.springframework.boot.context.config.AnsiOutputApplicationListener,\
org.springframework.boot.context.config.DelegatingApplicationListener,\
org.springframework.boot.context.logging.LoggingApplicationListener,\
org.springframework.boot.env.EnvironmentPostProcessorApplicationListener
EnvironmentPostProcessorApplicationListener 的 onApplicationEvent()方法
java
public void onApplicationEvent(ApplicationEvent event) {
if (event instanceof ApplicationEnvironmentPreparedEvent environmentPreparedEvent) {
this.onApplicationEnvironmentPreparedEvent(environmentPreparedEvent);
}
if (event instanceof ApplicationPreparedEvent) {
this.onApplicationPreparedEvent();
}
if (event instanceof ApplicationFailedEvent) {
this.onApplicationFailedEvent();
}
}
调用下面的方法:
java
private void onApplicationEnvironmentPreparedEvent(ApplicationEnvironmentPreparedEvent event) {
ConfigurableEnvironment environment = event.getEnvironment();
SpringApplication application = event.getSpringApplication();
Iterator var4 = this.getEnvironmentPostProcessors(application.getResourceLoader(), event.getBootstrapContext()).iterator();
while(var4.hasNext()) {
EnvironmentPostProcessor postProcessor = (EnvironmentPostProcessor)var4.next();
postProcessor.postProcessEnvironment(environment, application);
}
}
java
public interface EnvironmentPostProcessor {
void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application);
}
有8个实现类
3、创建上下文
java
context = this.createApplicationContext();
java
protected ConfigurableApplicationContext createApplicationContext() {
return this.applicationContextFactory.create(this.webApplicationType);
}
有三个上下文创建工厂
java
// 创建的ServletWebServerApplicationContext
private ConfigurableApplicationContext createContext() {
return (ConfigurableApplicationContext)(!AotDetector.useGeneratedArtifacts() ? new AnnotationConfigServletWebServerApplicationContext() : new ServletWebServerApplicationContext());
}
4. 上下文准备
java
this.prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);
java
private void prepareContext(DefaultBootstrapContext bootstrapContext, ConfigurableApplicationContext context, ConfigurableEnvironment environment, SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments, Banner printedBanner) {
// 设置环境到应用上下文中
context.setEnvironment(environment);
// 执行自定义的应用上下文后处理器
this.postProcessApplicationContext(context);
// 如果有必要,添加AOT(Ahead-Of-Time)生成的初始化器
this.addAotGeneratedInitializerIfNecessary(this.initializers);
// 应用所有注册的初始化器
this.applyInitializers(context);
// 通知监听器上下文已经准备好了
listeners.contextPrepared(context);
// 关闭引导上下文并传递应用上下文
bootstrapContext.close(context);
// 如果允许打印启动信息,则打印
if (this.logStartupInfo) {
// 打印启动信息,如果父上下文不存在则更详细
this.logStartupInfo(context.getParent() == null);
// 打印激活的配置文件信息
this.logStartupProfileInfo(context);
}
// 获取应用上下文中的bean工厂
ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
// 注册applicationArguments为单例bean
beanFactory.registerSingleton("springApplicationArguments", applicationArguments);
// 如果有打印的banner,则也注册为单例bean
if (printedBanner != null) {
beanFactory.registerSingleton("springBootBanner", printedBanner);
}
// 如果bean工厂支持自动装配能力,则设置是否允许循环依赖
if (beanFactory instanceof AbstractAutowireCapableBeanFactory autowireCapableBeanFactory) {
autowireCapableBeanFactory.setAllowCircularReferences(this.allowCircularReferences);
// 如果是默认的bean工厂,则设置是否允许覆盖bean定义
if (beanFactory instanceof DefaultListableBeanFactory listableBeanFactory) {
listableBeanFactory.setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
}
}
// 如果是懒加载模式,则添加懒加载的bean工厂后处理器
if (this.lazyInitialization) {
context.addBeanFactoryPostProcessor(new LazyInitializationBeanFactoryPostProcessor());
}
// 如果需要保持存活,则添加KeepAlive应用监听器
if (this.keepAlive) {
context.addApplicationListener(new KeepAlive());
}
// 添加一个用于处理属性源顺序的bean工厂后处理器
context.addBeanFactoryPostProcessor(new PropertySourceOrderingBeanFactoryPostProcessor(context));
// 如果没有使用AOT生成的类,则加载所有的配置源
if (!AotDetector.useGeneratedArtifacts()) {
Set<Object> sources = this.getAllSources();
// 断言配置源不为空
Assert.notEmpty(sources, "Sources must not be empty");
// 加载配置源
this.load(context, sources.toArray(new Object[0]));
}
// 通知监听器上下文已经加载完毕
listeners.contextLoaded(context);
}
其中 loader.load(); 会跳转到 BeanDefinitionLoader#load(java.lang.Class<?>) 方法中。
java
private void load(Class<?> source) {
if (this.isGroovyPresent() && GroovyBeanDefinitionSource.class.isAssignableFrom(source)) {
GroovyBeanDefinitionSource loader = (GroovyBeanDefinitionSource)BeanUtils.instantiateClass(source, GroovyBeanDefinitionSource.class);
((GroovyBeanDefinitionReader)this.groovyReader).beans(loader.getBeans());
}
if (this.isEligible(source)) {
this.annotatedReader.register(new Class[]{source});
}
}
java
private <T> void doRegisterBean(Class<T> beanClass, @Nullable String name, @Nullable Class<? extends Annotation>[] qualifiers, @Nullable Supplier<T> supplier, @Nullable BeanDefinitionCustomizer[] customizers) {
// 创建一个新的AnnotatedGenericBeanDefinition实例,该实例描述了Bean的元数据
AnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition(beanClass);
// 使用ConditionEvaluator检查BeanDefinition的条件注解,确定是否应该跳过此Bean的注册
if (!this.conditionEvaluator.shouldSkip(abd.getMetadata())) {
// 标记此BeanDefinition为候选Bean
abd.setAttribute(ConfigurationClassUtils.CANDIDATE_ATTRIBUTE, Boolean.TRUE);
// 设置Bean的实例化策略
abd.setInstanceSupplier(supplier);
// 解析作用域元数据
ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(abd);
// 设置Bean的作用域
abd.setScope(scopeMetadata.getScopeName());
// 生成或使用提供的Bean名称
String beanName = name != null ? name : this.beanNameGenerator.generateBeanName(abd, this.registry);
// 处理一些通用的Bean定义注解,如@DependsOn, @DependsFor等
AnnotationConfigUtils.processCommonDefinitionAnnotations(abd);
// 如果提供了限定符注解数组
if (qualifiers != null) {
Class<? extends Annotation>[] var9 = qualifiers;
int var10 = qualifiers.length;
// 遍历限定符注解
for(int var11 = 0; var11 < var10; ++var11) {
Class<? extends Annotation> qualifier = var9[var11];
// 如果限定符注解是@Primary,则标记此Bean为首选Bean
if (Primary.class == qualifier) {
abd.setPrimary(true);
} else if (Lazy.class == qualifier) {
// 如果限定符注解是@Lazy,则设置此Bean为延迟初始化
abd.setLazyInit(true);
} else {
// 否则,创建一个新的AutowireCandidateQualifier实例并添加到BeanDefinition
abd.addQualifier(new AutowireCandidateQualifier(qualifier));
}
}
}
// 如果提供了BeanDefinitionCustomizer数组
if (customizers != null) {
BeanDefinitionCustomizer[] var13 = customizers;
int var10 = customizers.length;
// 遍历定制器并应用它们
for(int var11 = 0; var11 < var10; ++var11) {
BeanDefinitionCustomizer customizer = var13[var11];
customizer.customize(abd);
}
}
// 创建一个BeanDefinitionHolder实例,包含BeanDefinition和Bean名称
BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(abd, beanName);
// 应用作用域代理模式
definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
// 注册BeanDefinition到BeanFactory
BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry);
}
}
这个方法的主要功能包括:
- 创建一个新的AnnotatedGenericBeanDefinition来描述Bean的定义。
- 检查条件注解,决定是否应该跳过Bean的注册。
- 设置Bean的实例化策略。
- 设置Bean的作用域。
- 生成或使用提供的Bean名称。
- 处理通用的Bean定义注解。
- 根据提供的限定符注解设置Bean的优先级和初始化策略。
- 应用任何提供的BeanDefinitionCustomizer。
- 创建BeanDefinitionHolder,并应用作用域代理模式。
- 将BeanDefinition注册到Spring的BeanFactory中。