SpringBoot启动流程

Java程序的启动入口是在main方法。因此如果我们要了解SpringBoot的启动流程,那么我们可以从main着手

入口

1
2
3
4
5
6
7
8
9
public class SpringbootApplication {
public static void main(String[] args) {
SpringApplication.run(SpringbootApplication.class, args);
}
}

public static ConfigurableApplicationContext run(Object[] sources, String[] args) {
return new SpringApplication(sources).run(args);
}

构造SpringApplication

构造SpringApplication对象。在其内部进行初始化操作

1
2
3
4
5
6
7
8
9
10
private void initialize(Object[] sources) {
if (sources != null && sources.length > 0) {
this.sources.addAll(Arrays.asList(sources));
}
this.webEnvironment = deduceWebEnvironment();
setInitializers((Collection) getSpringFactoriesInstances(
ApplicationContextInitializer.class));
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
this.mainApplicationClass = deduceMainApplicationClass();
}

判断是否是Web程序

首先将当前类添加到启动类中,判断是否是Web程序

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
private boolean deduceWebEnvironment() {
for (String className : WEB_ENVIRONMENT_CLASSES) {
if (!ClassUtils.isPresent(className, null)) {
return false;
}
}
return true;
}
public static boolean isPresent(String className, ClassLoader classLoader) {
try {
forName(className, classLoader);
return true;
}
catch (Throwable ex) {
// Class or one of its dependencies is not present...
return false;
}
}

通过判断javax.servlet.Servlet,org.springframework.web.context.ConfigurableWebApplicationContext能否被加载类确定是否是Web程序

找出所有应用初始化器

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
private <T> Collection<? extends T> getSpringFactoriesInstances(Class<T> type,
Class<?>[] parameterTypes, Object... args) {
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
// Use names and ensure unique to protect against duplicates
Set<String> names = new LinkedHashSet<String>(
SpringFactoriesLoader.loadFactoryNames(type, classLoader));
List<T> instances = createSpringFactoriesInstances(type, parameterTypes,
classLoader, args, names);
AnnotationAwareOrderComparator.sort(instances);
return instances;
}

private <T> List<T> createSpringFactoriesInstances(Class<T> type,
Class<?>[] parameterTypes, ClassLoader classLoader, Object[] args,
Set<String> names) {
List<T> instances = new ArrayList<T>(names.size());
for (String name : names) {
try {
Class<?> instanceClass = ClassUtils.forName(name, classLoader);
Assert.isAssignable(type, instanceClass);
Constructor<?> constructor = instanceClass
.getDeclaredConstructor(parameterTypes);
T instance = (T) BeanUtils.instantiateClass(constructor, args);
instances.add(instance);
}
catch (Throwable ex) {
throw new IllegalArgumentException(
"Cannot instantiate " + type + " : " + name, ex);
}
}
return instances;
}

spring.factories文件中找出keyApplicationContextInitializer的类实例并实例化,默认情况下从spring.factories文件中找出的keyApplicationContextInitializer的类有以下五种:

  1. org.springframework.boot.context.config.DelegatingApplicationContextInitializer
  2. org.springframework.boot.context.ContextIdApplicationContextInitializer
  3. org.springframework.boot.context.ConfigurationWarningsApplicationContextInitializer
  4. org.springframework.boot.context.web.ServerPortInfoApplicationContextInitializer
  5. org.springframework.boot.autoconfigure.logging.AutoConfigurationReportLoggingInitializer

找出所有应用程序监听器

spring.factories中找出所有keyApplicationListener的应用程序监听器,过程跟找出应用程序初始化器一致。

默认情况下,被加载的应用程序监听器有

  1. org.springframework.boot.context.config.ConfigFileApplicationListener
  2. org.springframework.boot.context.config.AnsiOutputApplicationListener
  3. org.springframework.boot.logging.LoggingApplicationListener
  4. org.springframework.boot.logging.ClasspathLoggingApplicationListener
  5. org.springframework.boot.autoconfigure.BackgroundPreinitializer
  6. org.springframework.boot.context.config.DelegatingApplicationListener
  7. org.springframework.boot.builder.ParentContextCloserApplicationListener
  8. org.springframework.boot.ClearCachesApplicationListener
  9. org.springframework.boot.context.FileEncodingApplicationListener
  10. org.springframework.boot.liquibase.LiquibaseServiceLocatorApplicationListener

这些监听器在应用程序启动之后会回调执行对应的逻辑操作

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
public ConfigurableApplicationContext run(String... args) {
StopWatch stopWatch = new StopWatch();
stopWatch.start();
ConfigurableApplicationContext context = null;
FailureAnalyzers analyzers = null;
configureHeadlessProperty();
SpringApplicationRunListeners listeners = getRunListeners(args);
listeners.starting();
try {
ApplicationArguments applicationArguments = new DefaultApplicationArguments(
args);
ConfigurableEnvironment environment = prepareEnvironment(listeners,
applicationArguments);
Banner printedBanner = printBanner(environment);
context = createApplicationContext();
analyzers = new FailureAnalyzers(context);
prepareContext(context, environment, listeners, applicationArguments,
printedBanner);
refreshContext(context);
afterRefresh(context, applicationArguments);
listeners.finished(context, null);
stopWatch.stop();
if (this.logStartupInfo) {
new StartupInfoLogger(this.mainApplicationClass)
.logStarted(getApplicationLog(), stopWatch);
}
return context;
}
catch (Throwable ex) {
handleRunFailure(context, listeners, analyzers, ex);
throw new IllegalStateException(ex);
}
}

首先构造StopWatch来统计每个任务的运行时间。

1
2
3
4
5
private SpringApplicationRunListeners getRunListeners(String[] args) {
Class<?>[] types = new Class<?>[] { SpringApplication.class, String[].class };
return new SpringApplicationRunListeners(logger, getSpringFactoriesInstances(
SpringApplicationRunListener.class, types, this, args));
}

获取所有的应用程序监听器,然后开始监听。构建DefaultApplicationArguments

1
2
3
4
5
6
7
8
9
10
11
12
13
private ConfigurableEnvironment prepareEnvironment(
SpringApplicationRunListeners listeners,
ApplicationArguments applicationArguments) {
// Create and configure the environment
ConfigurableEnvironment environment = getOrCreateEnvironment();
configureEnvironment(environment, applicationArguments.getSourceArgs());
listeners.environmentPrepared(environment);
if (!this.webEnvironment) {
environment = new EnvironmentConverter(getClassLoader())
.convertToStandardEnvironmentIfNecessary(environment);
}
return environment;
}

准备运行环境,获取或创建环境。配置属性,这个时候resources里的属性被读取。配置运行环境(profile)。回调监听器告知环境已经配置完成

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

打印Banner

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
protected ConfigurableApplicationContext createApplicationContext() {
Class<?> contextClass = this.applicationContextClass;
if (contextClass == null) {
try {
contextClass = Class.forName(this.webEnvironment
? DEFAULT_WEB_CONTEXT_CLASS : DEFAULT_CONTEXT_CLASS);
}
catch (ClassNotFoundException ex) {
throw new IllegalStateException(
"Unable create a default ApplicationContext, "
+ "please specify an ApplicationContextClass",
ex);
}
}
return (ConfigurableApplicationContext) BeanUtils.instantiate(contextClass);
}

创建应用程序上下文

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
private void prepareContext(ConfigurableApplicationContext context,
ConfigurableEnvironment environment, SpringApplicationRunListeners listeners,
ApplicationArguments applicationArguments, Banner printedBanner) {
context.setEnvironment(environment);
postProcessApplicationContext(context);
applyInitializers(context);
listeners.contextPrepared(context);
if (this.logStartupInfo) {
logStartupInfo(context.getParent() == null);
logStartupProfileInfo(context);
}

// Add boot specific singleton beans
context.getBeanFactory().registerSingleton("springApplicationArguments",
applicationArguments);
if (printedBanner != null) {
context.getBeanFactory().registerSingleton("springBootBanner", printedBanner);
}

// Load the sources
Set<Object> sources = getSources();
Assert.notEmpty(sources, "Sources must not be empty");
load(context, sources.toArray(new Object[sources.size()]));
listeners.contextLoaded(context);
}

准备上下文

1
2
3
4
5
6
7
8
9
10
11
private void refreshContext(ConfigurableApplicationContext context) {
refresh(context);
if (this.registerShutdownHook) {
try {
context.registerShutdownHook();
}
catch (AccessControlException ex) {
// Not allowed in some environments.
}
}
}

刷新上下文

所有的这些过程都会通过SpringApplicationRunListener对外发送SpringApplicationEvent事件,这是一个订阅发布模式

总结

SpringBoot启动时,会加载各种初始化器,监听器,然后会通过订阅发布模式对所有的监听者发送启动过程