springboot 启动

@SpringBootApplication

用来开启自动配置
todo

SpringApplication.run(xxx.class, args)

先看看启动类:SpringApplication

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
// primarySource 主要用来扫包,拿到主类的地址,并向下扫包
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);
}
// 实例化 SpringApplication
public SpringApplication(Class<?>... primarySources) {
this(null, primarySources);
}
@SuppressWarnings({ "unchecked", "rawtypes" })
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
this.resourceLoader = resourceLoader;
Assert.notNull(primarySources, "PrimarySources must not be null");
this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
// 这句话用来判断当前的web环境,是reactive 还是 servlet
this.webApplicationType = WebApplicationType.deduceFromClasspath();
// 设置执行refresh 之前的初始化操作
// ApplicationContextInitializer.class 该类的作用是:在执行refresh之前的回调,也就是前置处理事件,主要用来做初始化工作
setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
// 注册事件监听器
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
// 寻找程序启动类,为什么不用:primarySources
// 因为:primarySource 主要用来确定扫包路径,但是并不等于一定是启动类,所有通过异常的形式,确定main的位置,
this.mainApplicationClass = deduceMainApplicationClass();
}

下面开始执行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
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
102
103
104
105
106
107
108
109
110
111
112
113
// 运行Spring应用程序,创建并刷新一个新的ApplicationContext。
public ConfigurableApplicationContext run(String... args) {
// 计时器, 主要用来计时启动事件
StopWatch stopWatch = new StopWatch();
stopWatch.start();
// 创建上下文,区别于ApplicationContext, 这个在ApplicationContext的基础上增加了可配置的方法,即重写数据
ConfigurableApplicationContext context = null;
Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
// 该硬件是否是无头模式(即:是否有显示器、鼠标等硬件)默认:false
configureHeadlessProperty();
SpringApplicationRunListeners listeners = getRunListeners(args);
listeners.starting();
try {
//
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);
configureIgnoreBeanInfo(environment);
// 输出banner日志信息
Banner printedBanner = printBanner(environment);
// 创建默认的applicationContext
// 创建相应环境的applicationContext
context = createApplicationContext();
// 加载启动异常报告器
exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class,
new Class[] { ConfigurableApplicationContext.class }, context);
// 准备工作:设置环境参数、前置事件
prepareContext(context, environment, listeners, applicationArguments, printedBanner);
refreshContext(context);
afterRefresh(context, applicationArguments);
// 关闭计时器
stopWatch.stop();
if (this.logStartupInfo) {
// 启动信息输出
new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch);
}
listeners.started(context);
callRunners(context, applicationArguments);
}
catch (Throwable ex) {
handleRunFailure(context, ex, exceptionReporters, listeners);
throw new IllegalStateException(ex);
}

try {
listeners.running(context);
}
catch (Throwable ex) {
handleRunFailure(context, ex, exceptionReporters, null);
throw new IllegalStateException(ex);
}
return context;
}

private SpringApplicationRunListeners getRunListeners(String[] args) {
// 构造方法入参,固定的两个参数,也就是说实现 SpringApplicationRunListener的接口必须实现一个只包含这两个参数的构造方法,例如下图展示的一样
Class<?>[] types = new Class<?>[] { SpringApplication.class, String[].class };
// SpringApplicationRunListener applicationContext 加载前的监听事件,此时并没有开始refresh操作
// 也可以理解为对run方法的前置监听
// SpringApplicationRunListeners 是SpringApplicationRunListener的包装器,用来统一管理listener
return new SpringApplicationRunListeners(logger,
getSpringFactoriesInstances(SpringApplicationRunListener.class, types, this, args));
}
private <T> Collection<T> getSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, Object... args) {
ClassLoader classLoader = getClassLoader();
// Use names and ensure unique to protect against duplicates
Set<String> names = new LinkedHashSet<>(SpringFactoriesLoader.loadFactoryNames(type, classLoader));
List<T> instances = createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);
AnnotationAwareOrderComparator.sort(instances);
return instances;
}


/**
* 该context适用在没有web环境的
*/
public static final String DEFAULT_CONTEXT_CLASS = "org.springframework.context."
+ "annotation.AnnotationConfigApplicationContext";

/**
* servlet环境的applicationContext
*/
public static final String DEFAULT_SERVLET_WEB_CONTEXT_CLASS = "org.springframework.boot."
+ "web.servlet.context.AnnotationConfigServletWebServerApplicationContext";

/**
* reactive环境的applicationContext
*/
public static final String DEFAULT_REACTIVE_WEB_CONTEXT_CLASS = "org.springframework."
+ "boot.web.reactive.context.AnnotationConfigReactiveWebServerApplicationContext";

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);
}

加载 META-INF/spring.factories

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
public static List<String> loadFactoryNames(Class<?> factoryType, @Nullable ClassLoader classLoader) {
String factoryTypeName = factoryType.getName();
return loadSpringFactories(classLoader).getOrDefault(factoryTypeName, Collections.emptyList());
}
// 解析spring.factories , 转化为 map形式
private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) {
// 是否有缓存
MultiValueMap<String, String> result = cache.get(classLoader);
if (result != null) {
return result;
}
// 第一次获取和解析, 顺序为文件中写的顺序
try {
Enumeration<URL> urls = (classLoader != null ?
classLoader.getResources(FACTORIES_RESOURCE_LOCATION) :
ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION));
result = new LinkedMultiValueMap<>();
while (urls.hasMoreElements()) {
URL url = urls.nextElement();
UrlResource resource = new UrlResource(url);
Properties properties = PropertiesLoaderUtils.loadProperties(resource);
for (Map.Entry<?, ?> entry : properties.entrySet()) {
String factoryTypeName = ((String) entry.getKey()).trim();
for (String factoryImplementationName : StringUtils.commaDelimitedListToStringArray((String) entry.getValue())) {
result.add(factoryTypeName, factoryImplementationName.trim());
}
}
}
cache.put(classLoader, result);
return result;
}
catch (IOException ex) {
throw new IllegalArgumentException("Unable to load factories from location [" +
FACTORIES_RESOURCE_LOCATION + "]", ex);
}
}