Spring Boot启动过程源码分析

[toc]

Application实例化

Spring Boot的启动始于:

1
SpringApplication.run(DemoApplication.class, args);

相应实现:

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

它实际上会构造一个SpringApplication的实例,然后运行它的run方法:

1
2
3
public SpringApplication(Object... sources) {
initialize(sources);
}
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();
}

deduceWebEnvironment()是推断应用类型是Standard还是Web,方法是在当类路径中找是否存在”javax.servlet.Servlet”,”org.springframework.web.context.ConfigurableWebApplicationContext”的类来判断的。

然后设置初始化器,会从类路径的META-INF/spring.factories处读取相应配置文件,读取配置文件中Key为:org.springframework.context.ApplicationContextInitializer的value。以spring-boot这个包为例,它的META-INF/spring.factories部分定义如下所示:

1
2
3
4
5
6
# Application Context Initializers
org.springframework.context.ApplicationContextInitializer=\
org.springframework.boot.context.ConfigurationWarningsApplicationContextInitializer,\
org.springframework.boot.context.ContextIdApplicationContextInitializer,\
org.springframework.boot.context.config.DelegatingApplicationContextInitializer,\
org.springframework.boot.context.embedded.ServerPortInfoApplicationContextInitializer

因此这几个类名会实例化出来放在SpringApplication 的initializers中。

之后设置监听器,同上读取配置文件中Key为:org.springframework.context. ApplicationListener的value,然后加载实例化后,设置在listeners中。

1
2
3
4
5
6
7
8
9
10
11
# Application Listeners
org.springframework.context.ApplicationListener=\
org.springframework.boot.ClearCachesApplicationListener,\
org.springframework.boot.builder.ParentContextCloserApplicationListener,\
org.springframework.boot.context.FileEncodingApplicationListener,\
org.springframework.boot.context.config.AnsiOutputApplicationListener,\
org.springframework.boot.context.config.ConfigFileApplicationListener,\
org.springframework.boot.context.config.DelegatingApplicationListener,\
org.springframework.boot.liquibase.LiquibaseServiceLocatorApplicationListener,\
org.springframework.boot.logging.ClasspathLoggingApplicationListener,\
org.springframework.boot.logging.LoggingApplicationListener

spring boot支持的事件监听类型有如下四种:ApplicationStartedEvent、ApplicationEnvironmentPreparedEvent、ApplicationPreparedEvent、ApplicationFailedEvent。

然后设置mainApplicationClass:

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

它通过构造一个运行时异常,通过异常栈中方法名为main的栈帧来得到入口类的名字。至此,对于SpringApplication实例的初始化过程就结束了。

Application#run()

完成了实例化,下面开始调用run方法。流程图如下:

img

源码:

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
public ConfigurableApplicationContext run(String... args) {
// 计时工具
StopWatch stopWatch = new StopWatch();
stopWatch.start();

ConfigurableApplicationContext context = null;
FailureAnalyzers analyzers = null;
// 设置java.awt.headless系统属性为true - 没有图形化界面
configureHeadlessProperty();

SpringApplicationRunListeners listeners = getRunListeners(args);
listeners.starting();
try {
ApplicationArguments applicationArguments = new DefaultApplicationArguments(
args);
ConfigurableEnvironment environment = prepareEnvironment(listeners,
applicationArguments);

// Banner打印器,就是启动Spring Boot的时候打印在console上的
Banner printedBanner = printBanner(environment);

// 创建Spring上下文
context = createApplicationContext();
analyzers = new FailureAnalyzers(context);

// Spring上下文前置处理
prepareContext(context, environment, listeners, applicationArguments,
printedBanner);

refreshContext(context);

// Spring上下文后置处理
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);
}
}

第23行createApplicationContext()即创建Spring的主要组件ApplicationContext,对于Web应用,上ApplicationContext就是AnnotationConfigEmbeddedWebApplicationContext。

第30行refreshContext(context)即刷新ApplicationContext:

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.
}
}
}

最终会调用到我们熟知的AbstractApplicationContext的refresh()方法。

第33行上下文后置处理afterRefresh()方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
protected void afterRefresh(ConfigurableApplicationContext context,
ApplicationArguments args) {
callRunners(context, args);
}

private void callRunners(ApplicationContext context, ApplicationArguments args) {
List<Object> runners = new ArrayList<Object>();
runners.addAll(context.getBeansOfType(ApplicationRunner.class).values());
runners.addAll(context.getBeansOfType(CommandLineRunner.class).values());
AnnotationAwareOrderComparator.sort(runners);
for (Object runner : new LinkedHashSet<Object>(runners)) {
if (runner instanceof ApplicationRunner) {
callRunner((ApplicationRunner) runner, args);
}
if (runner instanceof CommandLineRunner) {
callRunner((CommandLineRunner) runner, args);
}
}
}

所谓的后置操作,就是在容器完成刷新后,依次调用注册的Runners。Runners可以是两个接口的实现类:org.springframework.boot.ApplicationRunner与org.springframework.boot.CommandLineRunner。

监听器Listener

再来看监听器是如何工作的呢?还是看上面ConfigurableApplicationContext#run()方法中第11行getRunListeners(),该方法源码如下:

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

这里的getSpringFactoriesInstances(SpringApplicationRunListener.class, types, this, args),会在META-INF/spring.factories中找到:

1
2
3
# Run Listeners
org.springframework.boot.SpringApplicationRunListener=\
org.springframework.boot.context.event.EventPublishingRunListener

getSpringFactoriesInstances()返回了EventPublishingRunListener实例。EventPublishingRunListener的构造方法如下:

1
2
3
4
5
6
7
8
public EventPublishingRunListener(SpringApplication application, String[] args) {
this.application = application;
this.args = args;
this.initialMulticaster = new SimpleApplicationEventMulticaster();
for (ApplicationListener<?> listener : application.getListeners()) {
this.initialMulticaster.addApplicationListener(listener);
}
}

构造方法中将SpringApplication中的监听器添加到了SimpleApplicationEventMulticaster的实例multicaster中。

接下来ConfigurableApplicationContext.run()方法中调用listeners.starting()方法,来看下:

1
2
3
4
5
public void starting() {
for (SpringApplicationRunListener listener : this.listeners) {
listener.starting();
}
}
1
2
3
4
5
6
@Override
@SuppressWarnings("deprecation")
public void starting() {
this.initialMulticaster
.multicastEvent(new ApplicationStartedEvent(this.application, this.args));
}

在EventPublishingRunListener.starting()方法中,先创建一个ApplicationStartedEvent事件,将this.application传递进去,因此使用ApplicationStartedEvent监听器时可以获取SpringApplication实例。
SimpleApplicationEventMulticaster.multicastEvent():

1
2
3
4
@Override
public void multicastEvent(ApplicationEvent event) {
multicastEvent(event, resolveDefaultEventType(event));
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
@Override
public void multicastEvent(final ApplicationEvent event, ResolvableType eventType) {
ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
for (final ApplicationListener<?> listener : getApplicationListeners(event, type)) {
Executor executor = getTaskExecutor();
if (executor != null) {
executor.execute(new Runnable() {
@Override
public void run() {
invokeListener(listener, event);
}
});
}
else {
invokeListener(listener, event);
}
}
}

getApplicationListeners()获取对应ApplicationEvent的listener,获取完指定事件对应监听器后,通过Executor执行一个子线程执行invokeListener(listener, event),该函数会调用监听器listener.onApplicationEvent(event)方法。
在SpringApplication.run()方法执行中,依次调用了listeners.starting()、listeners.environmentPrepared(environment)、listeners.contextLoaded(context)分别对应了ApplicationStartedEvent、ApplicationEnvironmentPreparedEvent、ApplicationPreparedEvent事件。


自定义启动扩展

基于上面的了解,我们就可以在Spring Boot启动添加自定义的初始化器、监听器等。

添加定制化的初始化器:

1
2
3
4
5
6
7
8
9
10
11
public static void main(String[] args) {

// 创建SpringApplication的实例
SpringApplication app = new SpringApplication(Application.class);

// 添加定制的初始化器
app.addInitializers(new CustomApplicationContextInitializer());

// 执行SpringApplication实例的run方法
app.run(args);
}
1
2
3
4
5
6
7
8
public class CustomApplicationContextInitializer implements ApplicationContextInitializer {
private static final Logger LOGGER = LoggerFactory.getLogger(CustomApplicationContextInitializer.class);

@Override
public void initialize(ConfigurableApplicationContext applicationContext) {
LOGGER.info("自定义的初始化器的initialize方法被执行了");
}
}

点击并拖拽以移动

添加定制化的监听器:

1
app.addListeners(new CustomApplicationListener());
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
public class CustomApplicationListener implements ApplicationListener {
private static final Logger LOGGER = LoggerFactory.getLogger(CustomApplicationListener.class);

public void onApplicationEvent(ApplicationEvent event) {
// 监听ApplicationStartingEvent
if (event instanceof ApplicationStartedEvent) {
logInfo("ApplicationStartedEvent listened");
}

// 监听ApplicationEnvironmentPreparedEvent
else if (event instanceof ApplicationEnvironmentPreparedEvent) {
logInfo("ApplicationEnvironmentPreparedEvent listened");
}

// 监听ApplicationPreparedEvent
else if (event instanceof ApplicationPreparedEvent) {
logInfo("ApplicationPreparedEvent listened");
}


// 监听ApplicationReadyEvent
else if (event instanceof ApplicationReadyEvent) {
logInfo("ApplicationReadyEvent listened");
}

// 监听ApplicationFailedEvent
else if (event instanceof ApplicationFailedEvent) {
logInfo("ApplicationFailedEvent listened");
}
}

private void logInfo(String log) {
if (LOGGER.isInfoEnabled()) {
LOGGER.info(log);
}
}
}

点击并拖拽以移动

添加定制化的后置Runners:

1
2
3
4
5
6
7
8
9
10
11
12
@Component
@Order(2)
public class CustomApplicationRunner implements ApplicationRunner {
private static final Logger LOGGER = LoggerFactory.getLogger(CustomApplicationRunner.class);

@Override
public void run(ApplicationArguments arg) {
if (LOGGER.isInfoEnabled()) {
LOGGER.info("自定义ApplicationRunner运行了");
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
@Component
@Order(1)
public class CustomCommandLineRunner implements CommandLineRunner {
private static final Logger LOGGER = LoggerFactory.getLogger(CustomCommandLineRunner.class);

@Override
public void run(String... strings) throws Exception {
if (LOGGER.isInfoEnabled()) {
LOGGER.info("自定义CommandLineRunner运行了");
}
}
}

​ 自定义Runner的添加方式和上述的初始化器以及监听器有点不同,就是Runners直接通过@Component注解添加即可,借助于包扫描机制,它们会被注册到容器中。至于它们运行的顺序,则可以通过上述的@Order注解来完成标注,数值越小的Runner优先级越高,因为源码中有AnnotationAwareOrderComparator.sort(runners),因此上面代码中,CustomCommandLineRunner将先于CustomApplicationRunner被执行。

启动打印Banner:

扩展的方式也很简单,看源代码就清楚该怎么扩展了:

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

点击并拖拽以移动


转载自:
http://blog.csdn.net/dm_vincent/article/details/76735888
http://blog.csdn.net/dm_vincent/article/details/77151122