前言
上一篇我们一起简单了解了【从入门到放弃-MySQL】数据库连接过程分析-客户端,写完之后通读一遍,感觉分析的不是很透彻。有很多地方都没搞通,因此决定从Springboot源码开始从头研究下。
main 入口分析
1 | package com.springboot.demo; |
- 一个简单的springboot项目启动文件中 一行代码就能搞定。
我们从这一行代码开始看起。
SpringApplication::SpringApplication
1 | public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) { |
- 主要是初始化成员变量,比如参数列表,应用类型、监听器等。
getSpringFactoriesInstances
1 | private <T> Collection<T> getSpringFactoriesInstances(Class<T> type, |
这个方法主要是根据type类型获取配置中默认的类列表,并进行初始化。
- loadFactoryNames:从META-INF/spring.factories中获取type对应的配置类名称列表。
- createSpringFactoriesInstances:校验获取到的类是否是parameterTypes类的子类,并将获取到的类通过反射机制实例化,

SpringApplication::run
1 | /** |
StopWatch
是一个计时器工具类,这里先记录了项目的启动时间
变量初始化
各种变量初始化,用法在后面具体分析
configureHeadlessProperty
设置系统java.awt.headless属性,为true的话是告知系统不要指望显示器、鼠标、键盘等可以正常运行,这是一个服务端程序,用到这些外设的时候需要靠自己模拟
getRunListeners
获取SpringApplicationRunListeners各项监听器并实例化,这些监听器配置在spring.factories资源文件中。
prepareEnvironment
配置环境,如配置文件、系统变量等并通过监听器广播环境变量准备完毕事件。
printBanner
打印启动显示的banner。
createApplicationContext
根据webApplicationType初始化spring上下文
exceptionReporters
初始化配置的异常报告类
prepareContext
1 | private void prepareContext(ConfigurableApplicationContext context, |
- setEnvironment:设置上下文环境
- postProcessApplicationContext:上下文后置处理,默认没做什么事。
- applyInitializers:调用之前实例化的几个ApplicationContextInitializer类的initialize方法
- contextPrepared:向listeners发送上下文已准备完毕的通知。
- load:BeanDefinitionLoader可以加载各种bean,比如注解、XML、package等多种类型的bean,在后面利用BeanDefinitionLoader将这些beans都加载进上下文中。
- contextLoaded:向listeners发送上下文已加载完毕的通知。
refreshContext
1 |
|
- prepareRefresh:一些准备工作,比如设置启动时间、初始化资源、必须属性校验等。
- obtainFreshBeanFactory:通知子类刷新内置的beanFactory
- prepareBeanFactory:对容器的beanFactory做一些准备工作,比如设置classloader、设置&取消设置一些类的bean
invokeBeanFactoryPostProcessors:
主要看invokeBeanDefinitionRegistryPostProcessors方法,会调用ConfigurationClassPostProcessor::processConfigBeanDefinitions。
1
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
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
List<BeanDefinitionHolder> configCandidates = new ArrayList<>();
String[] candidateNames = registry.getBeanDefinitionNames();
for (String beanName : candidateNames) {
BeanDefinition beanDef = registry.getBeanDefinition(beanName);
if (ConfigurationClassUtils.isFullConfigurationClass(beanDef) ||
ConfigurationClassUtils.isLiteConfigurationClass(beanDef)) {
if (logger.isDebugEnabled()) {
logger.debug("Bean definition has already been processed as a configuration class: " + beanDef);
}
}
else if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)) {
configCandidates.add(new BeanDefinitionHolder(beanDef, beanName));
}
}
// Return immediately if no @Configuration classes were found
if (configCandidates.isEmpty()) {
return;
}
// Sort by previously determined @Order value, if applicable
configCandidates.sort((bd1, bd2) -> {
int i1 = ConfigurationClassUtils.getOrder(bd1.getBeanDefinition());
int i2 = ConfigurationClassUtils.getOrder(bd2.getBeanDefinition());
return Integer.compare(i1, i2);
});
// Detect any custom bean name generation strategy supplied through the enclosing application context
SingletonBeanRegistry sbr = null;
if (registry instanceof SingletonBeanRegistry) {
sbr = (SingletonBeanRegistry) registry;
if (!this.localBeanNameGeneratorSet) {
BeanNameGenerator generator = (BeanNameGenerator) sbr.getSingleton(CONFIGURATION_BEAN_NAME_GENERATOR);
if (generator != null) {
this.componentScanBeanNameGenerator = generator;
this.importBeanNameGenerator = generator;
}
}
}
if (this.environment == null) {
this.environment = new StandardEnvironment();
}
// Parse each @Configuration class
ConfigurationClassParser parser = new ConfigurationClassParser(
this.metadataReaderFactory, this.problemReporter, this.environment,
this.resourceLoader, this.componentScanBeanNameGenerator, registry);
Set<BeanDefinitionHolder> candidates = new LinkedHashSet<>(configCandidates);
Set<ConfigurationClass> alreadyParsed = new HashSet<>(configCandidates.size());
do {
parser.parse(candidates);
parser.validate();
Set<ConfigurationClass> configClasses = new LinkedHashSet<>(parser.getConfigurationClasses());
configClasses.removeAll(alreadyParsed);
// Read the model and create bean definitions based on its content
if (this.reader == null) {
this.reader = new ConfigurationClassBeanDefinitionReader(
registry, this.sourceExtractor, this.resourceLoader, this.environment,
this.importBeanNameGenerator, parser.getImportRegistry());
}
this.reader.loadBeanDefinitions(configClasses);
alreadyParsed.addAll(configClasses);
candidates.clear();
if (registry.getBeanDefinitionCount() > candidateNames.length) {
String[] newCandidateNames = registry.getBeanDefinitionNames();
Set<String> oldCandidateNames = new HashSet<>(Arrays.asList(candidateNames));
Set<String> alreadyParsedClasses = new HashSet<>();
for (ConfigurationClass configurationClass : alreadyParsed) {
alreadyParsedClasses.add(configurationClass.getMetadata().getClassName());
}
for (String candidateName : newCandidateNames) {
if (!oldCandidateNames.contains(candidateName)) {
BeanDefinition bd = registry.getBeanDefinition(candidateName);
if (ConfigurationClassUtils.checkConfigurationClassCandidate(bd, this.metadataReaderFactory) &&
!alreadyParsedClasses.contains(bd.getBeanClassName())) {
candidates.add(new BeanDefinitionHolder(bd, candidateName));
}
}
}
candidateNames = newCandidateNames;
}
}
while (!candidates.isEmpty());
// Register the ImportRegistry as a bean in order to support ImportAware @Configuration classes
if (sbr != null && !sbr.containsSingleton(IMPORT_REGISTRY_BEAN_NAME)) {
sbr.registerSingleton(IMPORT_REGISTRY_BEAN_NAME, parser.getImportRegistry());
}
if (this.metadataReaderFactory instanceof CachingMetadataReaderFactory) {
// Clear cache in externally provided MetadataReaderFactory; this is a no-op
// for a shared cache since it'll be cleared by the ApplicationContext.
((CachingMetadataReaderFactory) this.metadataReaderFactory).clearCache();
}
}ConfigurationClassParser:处理@Configuration/@Component等注解,扫描、注册包下的类
ConfigurationClassBeanDefinitionReader:处理@Import/@ImportResource/@Bean等注解。
将所有扫描到的bean都装载至registry
invokeBeanDefinitionRegistryPostProcessors:执行invokeBeanDefinitionRegistryPostProcessors回调
- invokeBeanFactoryPostProcessors:执行invokeBeanFactoryPostProcessors回调
- registerBeanPostProcessors:注册拦截创建bean的bean处理器
- initMessageSource:初始化消息源
- initApplicationEventMulticaster:初始化事件广播
- onRefresh:对一些特殊子类上下文中初始化一些特殊的bean,比如在ServletWebServerApplicationContext中就做了createWebServer的操作
- registerListeners:注册bean监听器
- finishBeanFactoryInitialization:实例化所有单例bean,比如我们之前分析的【从入门到放弃-MySQL】数据库连接过程分析-客户端dataSource就是在这一步实例化的。
finishRefresh
结束上下文更新,并发布事件。
callRunners
如果有ApplicationRunner或者CommandLineRunner类型的bean,则触发run函数,启动任务。
总结
至此,springboot就已经启动完毕。概述下主要的启动过程就是
- 初始化环境
- 初始化默认配置
- 初始化各类监听器、事件
- 创建上下文
- 在上下文中添加默认的bean
- 扫描文件、注解等各种类型的bean添加在上下文中
- 实例化各个bean
- 启动完毕