抱歉,您的浏览器无法访问本站
本页面需要浏览器支持(启用)JavaScript
了解详情 >

SpringBoot源码分析-启动过程

启动流程图

启动原理

我们开发任何一个Spring Boot项目,都会用到如下的启动类

1
2
3
4
5
6
@SpringBootApplication
public class ApplicationTest {
public static void main(String[] args) {
SpringApplication.run(ApplicationTest.class);
}
}

​ 从上面代码可以看出,Annotation定义(@SpringBootApplication)和类定义(SpringApplication.run)最为耀眼,所以要揭开SpringBoot的神秘面纱,我们要从这两位开始就可以了。

SpringBootApplication注解

@SpringBootApplication注解是Spring Boot的核心注解,它其实是一个组合注解:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(
excludeFilters = {@Filter(
type = FilterType.CUSTOM,
classes = {TypeExcludeFilter.class}
), @Filter(
type = FilterType.CUSTOM,
classes = {AutoConfigurationExcludeFilter.class}
)}
)
public @interface SpringBootApplication

虽然定义使用了多个Annotation进行了原信息标注,但实际上重要的只有三个Annotation:

  • @Configuration(@SpringBootConfiguration点开查看发现里面还是应用了@Configuration)
  • @EnableAutoConfiguration
  • @ComponentScan

即 @SpringBootApplication = (默认属性)@Configuration + @EnableAutoConfiguration + @ComponentScan。

所以,如果我们使用如下的SpringBoot启动类,整个SpringBoot应用依然可以与之前的启动类功能对等:

1
2
3
4
5
6
7
8
@Configuration
@EnableAutoConfiguration
@ComponentScan
public class ApplicationTest {
public static void main(String[] args) {
SpringApplication.run(ApplicationTest.class, args);
}
}

每次写这3个比较累,所以写一个@SpringBootApplication方便点。接下来分别介绍这3个Annotation。

@Configuration

这里的@Configuration对我们来说不陌生,它就是JavaConfig形式的Spring Ioc容器的配置类使用的那个@Configuration,SpringBoot社区推荐使用基于JavaConfig的配置形式,所以,这里的启动类标注了@Configuration之后,本身其实也是一个IoC容器的配置类。

@ComponentScan

@ComponentScan这个注解在Spring中很重要,它对应XML配置中的元素,@ComponentScan的功能其实就是自动扫描并加载符合条件的组件(比如@Component和@Repository等)或者bean定义,最终将这些bean定义加载到IoC容器中。

我们可以通过basePackages等属性来细粒度的定制@ComponentScan自动扫描的范围,如果不指定,则默认Spring框架实现会从声明@ComponentScan所在类的package进行扫描。

注:所以SpringBoot的启动类最好是放在root package下,因为默认不指定basePackages。

@EnableAutoConfiguration

@EnableAutoConfiguration注解是springboot 完成自动装配的核心注解,借助@Import的帮助,将所有符合自动配置条件的bean定义加载到IoC容器。

@EnableAutoConfiguration会根据类路径中的jar依赖为项目进行自动配置,如:添加了spring-boot-starter-web依赖,会自动添加Tomcat和Spring MVC的依赖,Spring Boot会对Tomcat和Spring MVC进行自动配置。

@EnableAutoConfiguration作为一个复合Annotation,其自身定义关键信息如下:

1
2
3
4
5
6
7
8
9
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import({AutoConfigurationImportSelector.class})
public @interface EnableAutoConfiguration {
...
}

其中,最关键的要属@Import(EnableAutoConfigurationImportSelector.class),借助EnableAutoConfigurationImportSelector,@EnableAutoConfiguration可以帮助SpringBoot应用将所有符合条件的@Configuration配置都加载到当前SpringBoot创建并使用的IoC容器。就像一只“八爪鱼”一样,借助于Spring框架原有的一个工具类:SpringFactoriesLoader的支持,@EnableAutoConfiguration可以智能的自动配置功效才得以大功告成!

SpringApplication执行流程

启动类

1
2
3
4
5
6
@SpringBootApplication
public class ApplicationTest {
public static void main(String[] args) {
SpringApplication.run(ApplicationTest.class);
}
}

接着会走几个run方法的重载

1
2
3
4
5
6
7
8
public static ConfigurableApplicationContext run(Class<?> primarySource, String... args) {
return run(new Class<?>[]{primarySource}, args);
}

public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {
//创建SpringApplication对象并调用run方法
return new SpringApplication(primarySources).run(args);
}

构造方法

如果我们使用的是SpringApplication的静态run方法,那么,这个方法里面首先要创建一个SpringApplication对象实例,然后调用这个创建好的SpringApplication的实例方法。在SpringApplication实例初始化的时候,它会提前做几件事情:

  • 根据classpath里面是否存在某个特征类(org.springframework.web.context.ConfigurableWebApplicationContext)来决定是否应该创建一个为Web应用使用的ApplicationContext类型。
  • 使用SpringFactoriesLoader在应用的classpath中查找并加载所有可用的ApplicationContextInitializer。
  • 使用SpringFactoriesLoader在应用的classpath中查找并加载所有可用的ApplicationListener。
  • 推断并设置main方法的定义类。

当程序开始执行之后,会先创建SpringApplication对象,会调用SpringApplication的构造方法,进行某些初始参数的设置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
//创建一个新的实例,这个应用程序的上下文将要从指定的来源加载Bean
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
//初始化资源加载器,默认为null
this.resourceLoader = resourceLoader;
//断言判断主要资源加载类不能为null
Assert.notNull(primarySources, "PrimarySources must not be null");
//初始化主要资源加载器,并去重
this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
//推断当前WEB应用类型,一共有三种:NONE,SERVLET,REACTIVE
this.webApplicationType = WebApplicationType.deduceFromClasspath();
//设置应用上线文初始化器,从"META-INF/spring.factories"读取ApplicationContextInitializer类的实例名称集合并去重,并进行set去重。(一共7个)
setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
//设置监听器,从"META-INF/spring.factories"读取ApplicationListener类的实例名称集合并去重,并进行set去重。(一共11个)
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
//推断主入口应用类,通过当前调用栈,获取Main方法所在类,并赋值给mainApplicationClass
this.mainApplicationClass = deduceMainApplicationClass();
}

主要流程如下

  1. 推断当前WEB应用类型
  2. 读取META-INF/spring.factories 初始化ApplicationContextInitializer和ApplicationListener
  3. 推断主入口类
deduceFromClasspath

在上述构造方法中,有一个判断应用类型的方法,用来判断当前应用程序的类型:

检查是存在比如是否存在特定类来判断类型,比如判断是否存在javax.servlet.Servlet,如果存在则判断为SERVLET类型。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/**
* 推断WEB类型
*
* @return
*/
static WebApplicationType deduceFromClasspath() {
if (ClassUtils.isPresent(WEBFLUX_INDICATOR_CLASS, null) && !ClassUtils.isPresent(WEBMVC_INDICATOR_CLASS, null)
&& !ClassUtils.isPresent(JERSEY_INDICATOR_CLASS, null)) {
return WebApplicationType.REACTIVE;
}
//如果不存在javax.servlet.Servlet和org.springframework.web.context.ConfigurableWebApplicationContext 则判断WEB类型为NONE
for (String className : SERVLET_INDICATOR_CLASSES) {
if (!ClassUtils.isPresent(className, null)) {
return WebApplicationType.NONE;
}
}
//如果存在javax.servlet.Servlet或者org.springframework.web.context.ConfigurableWebApplicationContext 则判断是SERVLET类型
return WebApplicationType.SERVLET;
}
WebApplicationType的类型

总共有三种环境:非web环境、web环境、reactive环境三种

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public enum WebApplicationType {

/**
* The application should not run as a web application and should not start an
* embedded web server.
* 这个application不应该作为一个web application运行,并且不应该启动嵌入式web server
*/
NONE,

/**
* The application should run as a servlet-based web application and should start an
* embedded servlet web server.
* 这个application应该作为一个基于servlet的web应用运行,并且应该启动一个嵌入式servlet web server
*/
SERVLET,

/**
* The application should run as a reactive web application and should start an
* embedded reactive web server.
* 这个application应该作为一个响应式web application运行, 并且应该启动-个嵌入式响应式web server
*/
REACTIVE;
读取spring.factories完成初始化

读取META-INF/spring.factories文件获取对应的类完成初始化

初始化ApplicationContextInitializer

ApplicationContextInitializer是spring组件spring-context组件中的一个接口,主要是spring ioc容器刷新之前的一个回调接口,用于处于自定义逻辑。

1
setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
初始化ApplicationListener

ApplicationContext事件机制是观察者设计模式的实现,通过ApplicationEvent类和ApplicationListener接口,可以实现ApplicationContext事件处理。

如果容器中有一个ApplicationListener Bean,每当ApplicationContext发布ApplicationEvent时,ApplicationListener Bean将自动被触发。这种事件机制都必须需要程序显示的触发。

其中spring有一些内置的事件,当完成某种操作时会发出某些事件动作。比如监听ContextRefreshedEvent事件,当所有的bean都初始化完成并被成功装载后会触发该事件,实现ApplicationListener接口可以收到监听动作,然后可以写自己的逻辑。

同样事件可以自定义、监听也可以自定义,完全根据自己的业务逻辑来处理。

1
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
deduceMainApplicationClass

推断主入口应用类

1
2
3
4
5
6
7
8
9
10
11
12
13
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;
}

​ 基本流程就是创建一个运行时异常,然后获得堆栈数组,遍历StackTraceElement数组,判断方法名称是否为“mian”,如果过是则通过Class.forName()方法创建Class对象。

启动服务

springboot启动的运行方法,可以看到主要是各种运行环境的准备工作

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
public ConfigurableApplicationContext run(String... args) {
//1、创建并启动计时监控类
StopWatch stopWatch = new StopWatch();
stopWatch.start();
//2、初始化应用上下文和异常报告集合
ConfigurableApplicationContext context = null;
Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
//3、设置系统属性“java.awt.headless”的值,默认为true,用于运行headless服务器,进行简单的图像处理,多用于在缺少显示屏、键盘或者鼠标时的系统配置,很多监控工具如jconsole 需要将该值设置为true
configureHeadlessProperty();
//4、创建所有spring运行监听器并发布应用启动事件,简单说的话就是获取SpringApplicationRunListener类型的实例(EventPublishingRunListener对象),并封装进SpringApplicationRunListeners对象,然后返回这个SpringApplicationRunListeners对象。说的再简单点,getRunListeners就是准备好了运行时监听器EventPublishingRunListener。
// 获取实现了SpringApplicationRunListener接口的实现类,通过SPI机制加载
// META-INF/spring.factories文件下的类
SpringApplicationRunListeners listeners = getRunListeners(args);

// 首先调用SpringApplicationRunListener的starting方法
listeners.starting();
try {
//5、初始化默认应用参数类
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);

//6、根据运行监听器和应用参数来准备spring环境
ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);
//将要忽略的bean的参数打开
configureIgnoreBeanInfo(environment);
//7、创建banner打印类
// 启动时打印banner
Banner printedBanner = printBanner(environment);

//8、创建应用上下文,可以理解为创建一个容器
context = createApplicationContext();

//9、准备异常报告器,用来支持报告关于启动的错误
// 获取SpringBootExceptionReporter接口的类,异常报告
exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class,
new Class[]{ConfigurableApplicationContext.class}, context);

//10、准备应用上下文,该步骤包含一个非常关键的操作,将启动类注入容器,为后续开启自动化提供基础
prepareContext(context, environment, listeners, applicationArguments, printedBanner);

//11、刷新应用上下文
// 核心方法,启动spring容器
refreshContext(context);
//12、应用上下文刷新后置处理,做一些扩展功能
afterRefresh(context, applicationArguments);

//13、停止计时监控类
stopWatch.stop();
//14、输出日志记录执行主类名、时间信息
if (this.logStartupInfo) {
new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch);
}
//15、发布应用上下文启动监听事件
listeners.started(context);

//16、执行所有的Runner运行器
// ApplicationRunner
// CommandLineRunner
// 获取这两个接口的实现类,并调用其run方法
callRunners(context, applicationArguments);
} catch (Throwable ex) {
handleRunFailure(context, ex, exceptionReporters, listeners);
throw new IllegalStateException(ex);
}

try {
//17、发布应用上下文就绪事件
// 最后调用running方法
listeners.running(context);
} catch (Throwable ex) {
handleRunFailure(context, ex, exceptionReporters, null);
throw new IllegalStateException(ex);
}
return context;
}

下面详细介绍各个启动的环节:

创建监控类

创建并启动计时监控类,可以看到记录当前任务的名称,默认是空字符串,然后记录当前springboot应用启动的开始时间。

1
2
StopWatch stopWatch = new StopWatch();
stopWatch.start();

详细源码如下

1
2
3
4
5
6
7
8
9
10
11
12
public void start() throws IllegalStateException {
this.start("");
}

public void start(String taskName) throws IllegalStateException {
if (this.currentTaskName != null) {
throw new IllegalStateException("Can't start StopWatch: it's already running");
} else {
this.currentTaskName = taskName;
this.startTimeNanos = System.nanoTime();
}
}
初始化应用上下文和异常报告集合
1
2
ConfigurableApplicationContext context = null;
Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
设置系统属性

设置系统属性java.awt.headless的值:

1
2
3
4
5
6
7
8
9
10
11
12
13
/*
* java.awt.headless模式是在缺少显示屏、键盘或者鼠标的系统配置
* 当配置了如下属性之后,应用程序可以执行如下操作:
* 1、创建轻量级组件
* 2、收集关于可用的字体、字体指标和字体设置的信息
* 3、设置颜色来渲染准备图片
* 4、创造和获取图像,为渲染准备图片
* 5、使用java.awt.PrintJob,java.awt.print.*和javax.print.*类里的方法进行打印
*/
private void configureHeadlessProperty() {
System.setProperty(SYSTEM_PROPERTY_JAVA_AWT_HEADLESS,
System.getProperty(SYSTEM_PROPERTY_JAVA_AWT_HEADLESS, Boolean.toString(this.headless)));
}
创建spring运行监听器

创建所有spring运行监听器并发布应用启动事件

SpringApplication实例初始化完成并且完成设置后,就开始执行run方法的逻辑了,方法执行伊始,首先遍历执行所有通过SpringFactoriesLoader可以查找到并加载的SpringApplicationRunListener。调用它们的started()方法,告诉这些SpringApplicationRunListener,“嘿,SpringBoot应用要开始执行咯!”。

1
2
3
4
5
6
7
//创建所有spring运行监听器并发布应用启动事件,简单说的话就是获取SpringApplicationRunListener类型的实例(EventPublishingRunListener对象),并封装进SpringApplicationRunListeners对象,然后返回这个SpringApplicationRunListeners对象。说的再简单点,getRunListeners就是准备好了运行时监听器EventPublishingRunListener。
// 获取实现了SpringApplicationRunListener接口的实现类,通过SPI机制加载
// META-INF/spring.factories文件下的类
SpringApplicationRunListeners listeners = getRunListeners(args);

// 首先调用SpringApplicationRunListener的starting方法
listeners.starting();
创建spring监听器
1
2
3
4
5
//创建spring监听器
private SpringApplicationRunListeners getRunListeners(String[] args) {
Class<?>[] types = new Class<?>[]{SpringApplication.class, String[].class};
return new SpringApplicationRunListeners(logger, getSpringFactoriesInstances(SpringApplicationRunListener.class, types, this, args));
}

​ getSpringFactoriesInstances方法是从META-INF/spring.factories文件下的类获取 SpringApplicationRunListener接口的所有实现类,但是只有一个实现类EventPublishingRunListener

创建监听器集合并返回

1
2
3
4
SpringApplicationRunListeners(Log log, Collection<? extends SpringApplicationRunListener> listeners) {
this.log = log;
this.listeners = new ArrayList<>(listeners);
}
启动监听
1
2
3
4
5
6
7
//循环遍历获取监听器
void starting() {
for (SpringApplicationRunListener listener : this.listeners) {
//调用监听器的starting方法
listener.starting();
}
}

EventPublishingRunListener实现类的starting方法

1
2
3
4
5
6
//此处的监听器可以看出是事件发布监听器,主要用来发布启动事件
@Override
public void starting() {
//这里是创建application事件‘applicationStartingEvent’
this.initialMulticaster.multicastEvent(new ApplicationStartingEvent(this.application, this.args));
}

发布事件的具体实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
//applicationStartingEvent是springboot框架最早执行的监听器,在该监听器执行started方法时,会继续发布事件,主要是基于spring的事件机制
@Override
public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {
ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
//获取线程池,如果为空则同步处理。这里线程池为空,还未初始化
Executor executor = getTaskExecutor();
for (ApplicationListener<?> listener : getApplicationListeners(event, type)) {
if (executor != null) {
//异步发送事件
executor.execute(() -> invokeListener(listener, event));
}
else {
//同步发送事件
invokeListener(listener, event);
}
}
}
初始化默认应用参数类

创建并配置当前Spring Boot应用将要使用的Environment(包括配置要使用的PropertySource以及Profile)。

1
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
1
2
3
4
5
public DefaultApplicationArguments(String... args) {
Assert.notNull(args, "Args must not be null");
this.source = new Source(args);
this.args = args;
}
准备运行环境

根据运行监听器和应用参数来准备spring环境

遍历调用所有SpringApplicationRunListener的environmentPrepared()的方法,告诉他们:“当前SpringBoot应用使用的Environment准备好了咯!”。

1
ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);

详细环境的准备

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
//详细环境的准备
private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners,
ApplicationArguments applicationArguments) {
// Create and configure the environment
// 获取或者创建应用环境
ConfigurableEnvironment environment = getOrCreateEnvironment();
// 配置应用环境,配置propertySource和activeProfiles
configureEnvironment(environment, applicationArguments.getSourceArgs());
//listeners环境准备,广播ApplicationEnvironmentPreparedEvent
ConfigurationPropertySources.attach(environment);
// 调用environmentPrepared方法
listeners.environmentPrepared(environment);
//将环境绑定给当前应用程序
bindToSpringApplication(environment);
//对当前的环境类型进行判断,如果不一致进行转换
if (!this.isCustomEnvironment) {
environment = new EnvironmentConverter(getClassLoader()).convertEnvironmentIfNecessary(environment,
deduceEnvironmentClass());
}
//配置propertySource对它自己的递归依赖
ConfigurationPropertySources.attach(environment);
return environment;
}
创建环境

获取或者创建应用环境,根据应用程序的类型可以分为servlet环境、标准环境(特殊的非web环境)和响应式环境

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
private ConfigurableEnvironment getOrCreateEnvironment() {
//存在则直接返回
if (this.environment != null) {
return this.environment;
}
//根据webApplicationType创建对应的Environment
switch (this.webApplicationType) {
case SERVLET:
return new StandardServletEnvironment();
case REACTIVE:
return new StandardReactiveWebEnvironment();
default:
return new StandardEnvironment();
}
}
配置应用环境
1
2
3
4
5
6
7
8
9
10
protected void configureEnvironment(ConfigurableEnvironment environment, String[] args) {
if (this.addConversionService) {
ConversionService conversionService = ApplicationConversionService.getSharedInstance();
environment.setConversionService((ConfigurableConversionService) conversionService);
}
//配置命令参数
configurePropertySources(environment, args);
//配置profiles
configureProfiles(environment, args);
}
创建banner打印类

如果SpringApplication的showBanner属性被设置为true,则打印banner。

1
Banner printedBanner = printBanner(environment);

打印类的详细操作过程

1
2
3
4
5
6
7
8
9
10
11
12
13
//打印类的详细操作过程
private Banner printBanner(ConfigurableEnvironment environment) {
if (this.bannerMode == Banner.Mode.OFF) {
return null;
}
ResourceLoader resourceLoader = (this.resourceLoader != null) ? this.resourceLoader
: new DefaultResourceLoader(getClassLoader());
SpringApplicationBannerPrinter bannerPrinter = new SpringApplicationBannerPrinter(resourceLoader, this.banner);
if (this.bannerMode == Mode.LOG) {
return bannerPrinter.print(environment, this.mainApplicationClass, logger);
}
return bannerPrinter.print(environment, this.mainApplicationClass, System.out);
}
创建应用的上下文

创建应用的上下文:根据不同哦那个的应用类型初始化不同的上下文应用类

根据用户是否明确设置了applicationContextClass类型以及初始化阶段的推断结果,决定该为当前SpringBoot应用创建什么类型的ApplicationContext并创建完成,然后根据条件决定是否添加ShutdownHook,决定是否使用自定义的BeanNameGenerator,决定是否使用自定义的ResourceLoader,当然,最重要的,将之前准备好的Environment设置给创建好的ApplicationContext使用。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
protected ConfigurableApplicationContext createApplicationContext() {
Class<?> contextClass = this.applicationContextClass;
if (contextClass == null) {
try {
switch (this.webApplicationType) {
case SERVLET:
contextClass = Class.forName(DEFAULT_SERVLET_WEB_CONTEXT_CLASS);
break;
case REACTIVE:
contextClass = Class.forName(DEFAULT_REACTIVE_WEB_CONTEXT_CLASS);
break;
default:
contextClass = Class.forName(DEFAULT_CONTEXT_CLASS);
}
} catch (ClassNotFoundException ex) {
throw new IllegalStateException(
"Unable create a default ApplicationContext, please specify an ApplicationContextClass", ex);
}
}
return (ConfigurableApplicationContext) BeanUtils.instantiateClass(contextClass);
}
准备异常报告器

准备异常报告器,用来支持报告关于启动的错误
获取SpringBootExceptionReporter接口的类,异常报告

1
2
exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class,
new Class[]{ConfigurableApplicationContext.class}, context);

从META-INF/spring.factories中加载SpringBootExceptionReporter接口类型的实现类,并通过反射实例化

1
2
3
4
5
6
7
8
9
10
11
private <T> Collection<T> getSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, Object... args) {
ClassLoader classLoader = getClassLoader();
// Use names and ensure unique to protect against duplicates
//从META-INF/spring.factories中加载对应类型的类的自动配置类
Set<String> names = new LinkedHashSet<>(SpringFactoriesLoader.loadFactoryNames(type, classLoader));
// 加载上来后反射实例化
List<T> instances = createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);
//对实例列表进行排序
AnnotationAwareOrderComparator.sort(instances);
return instances;
}
准备应用上下文

准备应用上下文,该步骤包含一个非常关键的操作,将启动类注入容器,为后续开启自动化提供基础

1
prepareContext(context, environment, listeners, applicationArguments, printedBanner);

详细准备过程

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
private void prepareContext(ConfigurableApplicationContext context, ConfigurableEnvironment environment,
SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments, Banner printedBanner) {
//应用上下文的environment
context.setEnvironment(environment);
//应用上下文后处理
postProcessApplicationContext(context);
//为上下文应用所有初始化器,执行容器中的applicationContextInitializer(spring.factories的实例),将所有的初始化对象放置到context对象中
//调用实现了ApplicationContextInitializer接口的初始化方法
applyInitializers(context);
//触发所有SpringApplicationRunListener监听器的ContextPrepared事件方法。添加所有的事件监听器
// 调用contextPrepared
listeners.contextPrepared(context);
//记录启动日志
if (this.logStartupInfo) {
logStartupInfo(context.getParent() == null);
logStartupProfileInfo(context);
}
// Add boot specific singleton beans
// 注册启动参数bean,将容器指定的参数封装成bean,注入容器
//添加Spring的一些单例Bean
ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
beanFactory.registerSingleton("springApplicationArguments", applicationArguments);
//设置banner
if (printedBanner != null) {
beanFactory.registerSingleton("springBootBanner", printedBanner);
}
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");
//将bean加载到上下文中
load(context, sources.toArray(new Object[0]));
//触发所有springapplicationRunListener监听器的contextLoaded事件方法,
listeners.contextLoaded(context);
}
postProcessApplicationContext

这里没有做任何的处理过程,因为beanNameGenerator和resourceLoader默认为空,可以方便后续做扩展处理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
protected void postProcessApplicationContext(ConfigurableApplicationContext context) {
if (this.beanNameGenerator != null) {
context.getBeanFactory().registerSingleton(AnnotationConfigUtils.CONFIGURATION_BEAN_NAME_GENERATOR,
this.beanNameGenerator);
}
if (this.resourceLoader != null) {
if (context instanceof GenericApplicationContext) {
((GenericApplicationContext) context).setResourceLoader(this.resourceLoader);
}
if (context instanceof DefaultResourceLoader) {
((DefaultResourceLoader) context).setClassLoader(this.resourceLoader.getClassLoader());
}
}
if (this.addConversionService) {
context.getBeanFactory().setConversionService(ApplicationConversionService.getSharedInstance());
}
}
进行初始化

ApplicationContext创建好之后,SpringApplication会再次借助Spring-FactoriesLoader,查找并加载classpath中所有可用的ApplicationContext-Initializer,然后遍历调用这些ApplicationContextInitializer的initialize(applicationContext)方法来对已经创建好的ApplicationContext进行进一步的处理。

1
2
3
4
5
6
7
8
protected void applyInitializers(ConfigurableApplicationContext context) {
for (ApplicationContextInitializer initializer : getInitializers()) {
Class<?> requiredType = GenericTypeResolver.resolveTypeArgument(initializer.getClass(),
ApplicationContextInitializer.class);
Assert.isInstanceOf(requiredType, context, "Unable to call initializer.");
initializer.initialize(context);
}
}
添加所有的事件监听器

遍历调用所有SpringApplicationRunListener的contextPrepared()方法。

1
2
3
4
5
void contextPrepared(ConfigurableApplicationContext context) {
for (SpringApplicationRunListener listener : this.listeners) {
listener.contextPrepared(context);
}
}
加载启动类

最核心的一步,将之前通过@EnableAutoConfiguration获取的所有配置以及其他形式的IoC容器配置加载到已经准备完毕的ApplicationContext。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
protected void load(ApplicationContext context, Object[] sources) {
if (logger.isDebugEnabled()) {
logger.debug("Loading source " + StringUtils.arrayToCommaDelimitedString(sources));
}
BeanDefinitionLoader loader = createBeanDefinitionLoader(getBeanDefinitionRegistry(context), sources);
if (this.beanNameGenerator != null) {
loader.setBeanNameGenerator(this.beanNameGenerator);
}
if (this.resourceLoader != null) {
loader.setResourceLoader(this.resourceLoader);
}
if (this.environment != null) {
loader.setEnvironment(this.environment);
}
loader.load();
}

加载Class文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
private int load(Object source) {
Assert.notNull(source, "Source must not be null");
if (source instanceof Class<?>) {
return load((Class<?>) source);
}
if (source instanceof Resource) {
return load((Resource) source);
}
if (source instanceof Package) {
return load((Package) source);
}
if (source instanceof CharSequence) {
return load((CharSequence) source);
}
throw new IllegalArgumentException("Invalid source type " + source.getClass());
}

这里会加载我们的启动类ApplicationTest,因为是一个class所以会走load((Class<?>) source)

springboot会优先选择groovy加载方式,找不到在选择java方式

1
2
3
4
5
6
7
8
9
10
11
12
13
private int load(Class<?> source) {
if (isGroovyPresent() && GroovyBeanDefinitionSource.class.isAssignableFrom(source)) {
// Any GroovyLoaders added in beans{} DSL can contribute beans here
GroovyBeanDefinitionSource loader = BeanUtils.instantiateClass(source, GroovyBeanDefinitionSource.class);
load(loader);
}
//使用注解进行加载
if (isComponent(source)) {
this.annotatedReader.register(source);
return 1;
}
return 0;
}

在这里面会判断是否包含@Component注解,如果包含则会注册到注解扫描器中,交给以后的PostProcessor处理

1
2
3
4
5
6
7
8
9
10
11
private boolean isComponent(Class<?> type) {
// This has to be a bit of a guess. The only way to be sure that this type is
// eligible is to make a bean definition out of it and try to instantiate it.
if (MergedAnnotations.from(type, SearchStrategy.TYPE_HIERARCHY).isPresent(Component.class)) {
return true;
}
// Nested anonymous classes are not eligible for registration, nor are groovy
// closures
return !type.getName().matches(".*\\$_.*closure.*") && !type.isAnonymousClass()
&& type.getConstructors() != null && type.getConstructors().length != 0;
}
触发contextLoaded事件

遍历调用所有SpringApplicationRunListener的contextLoaded()方法。

1
2
3
4
5
void contextLoaded(ConfigurableApplicationContext context) {
for (SpringApplicationRunListener listener : this.listeners) {
listener.contextLoaded(context);
}
}
刷新应用上下文

核心方法,启动spring容器

调用ApplicationContext的refresh()方法,完成IoC容器可用的最后一道工序。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
private void refreshContext(ConfigurableApplicationContext context) {
//调用父类的刷新方法
refresh(context);
if (this.registerShutdownHook) {
try {
context.registerShutdownHook();
} catch (AccessControlException ex) {
// Not allowed in some environments.
}
}
}

protected void refresh(ApplicationContext applicationContext) {
Assert.isInstanceOf(AbstractApplicationContext.class, applicationContext);
((AbstractApplicationContext) applicationContext).refresh();
}

接着就回到了Spring中的源码了

refresh
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
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// Prepare this context for refreshing.
//刷新上下文环境,初始化上下文环境,对系统的环境变量或者系统属性进行准备和校验
prepareRefresh();

// Tell the subclass to refresh the internal bean factory.
//初始化beanfactory,解析xml,相当于之前的xmlBeanfactory操作
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

// Prepare the bean factory for use in this context.
//为上下文准备beanfactory,对beanFactory的各种功能进行填充,如@autowired,设置spel表达式解析器,设置编辑注册器,添加applicationContextAwareprocessor处理器等等
prepareBeanFactory(beanFactory);

try {
// Allows post-processing of the bean factory in context subclasses.
//提供子类覆盖的额外处理,即子类处理自定义的beanfactorypostProcess
postProcessBeanFactory(beanFactory);

// Invoke factory processors registered as beans in the context.
//激活各种beanfactory处理器
invokeBeanFactoryPostProcessors(beanFactory);

// Register bean processors that intercept bean creation.
//注册拦截bean创建的bean处理器,即注册beanPostProcessor
registerBeanPostProcessors(beanFactory);

// Initialize message source for this context.
//初始化上下文中的资源文件如国际化文件的处理
initMessageSource();

// Initialize event multicaster for this context.
//初始化上下文事件广播器
initApplicationEventMulticaster();

// Initialize other special beans in specific context subclasses.
//给子类扩展初始化其他bean
onRefresh();

// Check for listener beans and register them.
//在所有的bean中查找listener bean,然后 注册到广播器中
registerListeners();

// Instantiate all remaining (non-lazy-init) singletons.
//初始化剩余的非懒惰的bean,即初始化非延迟加载的bean
finishBeanFactoryInitialization(beanFactory);

// Last step: publish corresponding event.
//发完成刷新过程,通知声明周期处理器刷新过程,同时发出ContextRefreshEvent通知别人
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();
}
}
}
应用上下文刷新后置处理

应用上下文刷新后置处理,做一些扩展功能

当前方法的代码是空的,可以做一些自定义的后置处理操作

1
2
protected void afterRefresh(ConfigurableApplicationContext context, ApplicationArguments args) {
}
停止计时监控类

计时监听器停止,并统计一些任务执行信息

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public void stop() throws IllegalStateException {
if (this.currentTaskName == null) {
throw new IllegalStateException("Can't stop StopWatch: it's not running");
} else {
long lastTime = System.nanoTime() - this.startTimeNanos;
this.totalTimeNanos += lastTime;
this.lastTaskInfo = new StopWatch.TaskInfo(this.currentTaskName, lastTime);
if (this.keepTaskList) {
this.taskList.add(this.lastTaskInfo);
}

++this.taskCount;
this.currentTaskName = null;
}
}
发布应用上下文启动完成事件

触发所有SpringapplicationRunListener监听器的started事件方法

1
2
3
4
5
void started(ConfigurableApplicationContext context) {
for (SpringApplicationRunListener listener : this.listeners) {
listener.started(context);
}
}
执行所有Runner执行器

执行所有applicationRunner和CommandLineRunner两种运行器

查找当前ApplicationContext中是否注册有CommandLineRunner,如果有,则遍历执行它们。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
private void callRunners(ApplicationContext context, ApplicationArguments args) {
List<Object> runners = new ArrayList<>();
runners.addAll(context.getBeansOfType(ApplicationRunner.class).values());
runners.addAll(context.getBeansOfType(CommandLineRunner.class).values());
AnnotationAwareOrderComparator.sort(runners);
for (Object runner : new LinkedHashSet<>(runners)) {
if (runner instanceof ApplicationRunner) {
callRunner((ApplicationRunner) runner, args);
}
if (runner instanceof CommandLineRunner) {
callRunner((CommandLineRunner) runner, args);
}
}
}
发布应用上下文就绪事件

触发所有springapplicationRunnListener将挺起的running事件方法

1
2
3
4
5
void running(ConfigurableApplicationContext context) {
for (SpringApplicationRunListener listener : this.listeners) {
listener.running(context);
}
}

评论