Spring Boot
Spring Boot启动流程
@SpringBootApplication注解
Spring Boot的启动,首先需要一个加了@SpringBootApplication
注解的启动类。
这个注解本质上,是由@EnableAutoConfiguration
、@SpringBootConfiguration
、@ComponentScan
三个注解连起来构成。
@EnableAutoConfiguration
最为核心会导入自动配置
AutoConfigurationImportSelector
类,这个类会将所有符合条件的@Configuration
配置都进行加载。@SpringBootConfiguration
等同于@Configuration
将当前类标记为配置类,加载到容器中。
@ComponentScan
自动扫描并加载符合条件的Bean
SpringApplication.run
方法
在run方法开始执行后,会经历如下4个阶段:
服务构建
构建SpringApplication本身。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
// 1. 将资源加载器、主方法类加载至内存中
this.resourceLoader = resourceLoader;
Assert.notNull(primarySources, "PrimarySources must not be null");
this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
// 2. 逐一判断对应的服务类是否存在,来确定Web服务的类型。默认是基于Servlet的Web服务,如Tomcat
this.webApplicationType = WebApplicationType.deduceFromClasspath();
// 3. 加载初始化类,读取所有"META-INF/spring.factories"文件中的
// 注册初始化、上下文初始化、监听器这三类配置
// Spring Boot和Spring Boot Autoconfigure这两个工程中配置了7个上下文初始化和8个监听器
this.bootstrapRegistryInitializers = new ArrayList<>(
getSpringFactoriesInstances(BootstrapRegistryInitializer.class)); // 没有默认的注册初始化配置
setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
// 通过StackWalker判断出main方法所在的类(大概率就是启动类本身)
this.mainApplicationClass = deduceMainApplicationClass();
}环境准备
SpringApplication.run就是进入环境准备阶段。
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
46public ConfigurableApplicationContext run(String... args) {
// ...
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);
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) {
if (ex instanceof AbandonedRunException) {
throw ex;
}
handleRunFailure(context, ex, listeners);
throw new IllegalStateException(ex);
}
try {
if (context.isRunning()) {
Duration timeTakenToReady = Duration.ofNanos(System.nanoTime() - startTime);
listeners.ready(context, timeTakenToReady);
}
}
catch (Throwable ex) {
if (ex instanceof AbandonedRunException) {
throw ex;
}
handleRunFailure(context, ex, null);
throw new IllegalStateException(ex);
}
return context;
}容器创建
填充容器