# SpringApplication.run()阶段
# 创建SpringApplication对象
创建实例
Class<?> instanceClass = ClassUtils.forName(name, classLoader)
1其中
classLoader
可以通过ClassUtils.getDefaultClassLoader()
获取,或者是SpringApplication
类中的public ClassLoader getClassLoader(){}
方法断言某个父类型是否是可分配子某个子类型,如果不是,也就是
subType
不是superType的实例,那么这个代码会抛出一个异常Assert.isAssignable(Class<?> superType, Class<?> subType);
运行SpringApplication.run()
的时候,在创建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();
}
2
3
4
5
6
7
8
9
10
11
在此构造器中,会初始化ApplicationListener
类型的监听器,ApplicationContextInitializer
以及BootstrapRegistryInitializer
,他们都是通过类的全限定名称获取的
,通过private <T> Collection<T> getSpringFactoriesInstances(Class<T> type) {}
方法,返回一个实例化的对象集合
,如果我们想要增加一些自己的ApplicationListener类型的监听器,我们只需要实现这个对应的接口就行
在对this.mainApplicationClass
赋值的时候,是调用下面这个方法
private Class<?> deduceMainApplicationClass() {
try {
StackTraceElement[] stackTrace = new RuntimeException().getStackTrace();
for (StackTraceElement stackTraceElement : stackTrace) {
if ("main".equals(stackTraceElement.getMethodName())) {
return Class.forName(stackTraceElement.getClassName());
}
}
}
catch (ClassNotFoundException ex) {
// Swallow and continue
}
return null;
}
2
3
4
5
6
7
8
9
10
11
12
13
14
其实也就是遍历找到我们自己的类,这个主类调用SpringApplication.run()
方法,启动springboot
# 执行run()方法
在此run()方法中,会先创建一个开始时间,官方是调用这个方法
long startTime = System.nanoTime();
然后会创建一个引导程序bootstrap
,createBootstrapContext()
方法是通过从上一个new对象获取到的bootstrapRegistryInitializers
中获取的
DefaultBootstrapContext bootstrapContext = createBootstrapContext();
然后设置系统属性configureHeadlessProperty()
,在此方法中,主要调用System.setProperty(...)
方法进行设置
然后会获取运行时的监听器
SpringApplicationRunListeners listeners = getRunListeners(args)
需要注意的是,获取运行时的监听器,并不是上一步new对象获取的
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
,在此处获取运行时监听器是获取SpringApplicationRunListener
这个类,方法为getSpringFactoriesInstances(SpringApplicationRunListener.class, types, this, args)
,最终会new SpringApplicationRunListeners()
一个新的对象,然后调用此运行时监听器中的starting()
方法,开始监听器
# 准备环境
ConfigurableEnvironment environment = prepareEnvironment(listeners, bootstrapContext, applicationArguments)
private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners,
DefaultBootstrapContext bootstrapContext, ApplicationArguments applicationArguments) {
// Create and configure the environment
ConfigurableEnvironment 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) {
environment = convertEnvironment(environment);
}
ConfigurationPropertySources.attach(environment);
return environment;
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
先获取或者创建(如果没有ConfigurableEnvironment
环境对象的话)一个环境,ConfigurableEnvironment environment = getOrCreateEnvironment()
对应的源码为
private ConfigurableEnvironment getOrCreateEnvironment() {
if (this.environment != null) {
return this.environment;
}
switch (this.webApplicationType) {
case SERVLET:
return new ApplicationServletEnvironment();
case REACTIVE:
return new ApplicationReactiveWebEnvironment();
default:
return new ApplicationEnvironment();
}
}
2
3
4
5
6
7
8
9
10
11
12
13
这个也就是选择根据当前的配置,选择一个合适的环境,this.webApplicationType
为SERVLET
,所以会创建一个servlet
环境,REACTIVE
是一个响应式,如果两个都不满足,那么就创建一个默认的,无论在switch
中选择哪一个,他们最终都是StandardEnvironment
类型的对象,此StandardEnvironment
对象的祖宗类是ConfigurableEnvironment
,也就是this.environment
对应的类型。并且在最后将环境绑定到应用的过程中,会将获取到的环境转换成ConfigurableEnvironment
对象(子到父的过程)
如果我们想要自定义环境的话,可以调用
SpringApplication
对象中的setEnvironment(ConfigurableEnvironment)
方法,如果没有调用此方法自定义环境,那么environment
就是null,不建议自定义环境
# 配置环境
在getOrCreateEnvironment()
方法中,会进行下面代码,配置环境
protected void configureEnvironment(ConfigurableEnvironment environment, String[] args) {
if (this.addConversionService) {
environment.setConversionService(new ApplicationConversionService());
}
configurePropertySources(environment, args);
configureProfiles(environment, args);
}
2
3
4
5
6
7
在上一步中,已经创建了预准备环境,选择一个合适的StandardEnvironment
对象,那么在这一步就需要对此预准备环境进行配置(我并没有发现什么)
判断一个对象是否是某个Class的实例,可以使用Assert.isInstanceOf(Class, instance)
进行判断,如果判断失败,会抛出一个异常
Assert.state(boolean,message)
此方法是断言状态,如果boolean
为false,那么会抛出一个异常,异常中的message就是此方法中的message
# 将环境绑定到应用
bindToSpringApplication(environment);
此方法的代码为,为了演示方便,我在application.yml
文件中,添加了以下以spring.main
开头的配置
spring:
main:
allow-circular-references: true
2
3
protected void bindToSpringApplication(ConfigurableEnvironment environment) {
try {
Binder.get(environment).bind("spring.main", Bindable.ofInstance(this));
}
catch (Exception ex) {
throw new IllegalStateException("Cannot bind to SpringApplication", ex);
}
}
2
3
4
5
6
7
8
- 通过当前环境,获取到一个Binder对象
bind()
的方法如下
public <T> BindResult<T> bind(String name, Bindable<T> target) {
return bind(ConfigurationPropertyName.of(name), target, null);
}
2
3
我的判断:这一步应该就是配置以
spring.main
开头的配置,将这些配置绑定到当前环境中
# 打印banner
Banner printedBanner = printBanner(environment)
# 创建应用的上下文context
protected ConfigurableApplicationContext createApplicationContext() {
return this.applicationContextFactory.create(this.webApplicationType);
}
2
3
会根据我们预准备环境中获取的环境,创建对应的context,然后将
ApplicationStartup
添加到此context
中
当创建好了context之后,会预准备context
,和预准备环境差不多,会进行context
的相关配置,代码如下
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 beans
ConfigurableListableBeanFactory 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());
}
// Load the sources
Set<Object> sources = getAllSources();
Assert.notEmpty(sources, "Sources must not be empty");
load(context, sources.toArray(new Object[0]));
listeners.contextLoaded(context);
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
将此context
添加到applicationRunListener
等对象中
根据我们的配置信息,设置是否允许循环引用
((AbstractAutowireCapableBeanFactory) beanFactory).setAllowCircularReferences(this.allowCircularReferences)
1
# 刷新context
private void refreshContext(ConfigurableApplicationContext context) {
if (this.registerShutdownHook) {
shutdownHook.registerApplicationContext(context);
}
refresh(context);
}
protected void refresh(ConfigurableApplicationContext applicationContext) {
applicationContext.refresh();
}
2
3
4
5
6
7
8
9
10