[SpringBoot 源码分析]SpringBoot 如何启动
- 2021 年 11 月 23 日
本文字数:8394 字
阅读完需:约 28 分钟
![[SpringBoot源码分析]SpringBoot如何启动](https://static001.geekbang.org/infoq/9a/9ae34783f6738017792311e03efb2b6e.jpeg)
SpringBoot 概念
SpringApplication 提供了从 main 方法开始的启动 spring 应用程序的便捷方法。
Spring Boot 基于 spring4.0 以后
特点
快速开发和构建微服务系统
内嵌容器,如 Tomcat、Undertow
自动加载
自动管理依赖
引言
那么上述的 springboot 有这么多好处,那先研究下 springboot 是怎么启动,后续我们再分篇研究下自动加载
开始分析源码
@SpringBootApplication(scanBasePackages = {"com.github.demo"})
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
// SpringApplication的run方法
public static ConfigurableApplicationContext run(Class<?> primarySource, String... args) {
return run(new Class<?>[] { primarySource }, args);
}
// 最终调用的SpringApplication的run方法
public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {
return new SpringApplication(primarySources).run(args);
}
初始化 SpringApplication
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
// 设置 resource
this.resourceLoader = resourceLoader;
Assert.notNull(primarySources, "PrimarySources must not be null");
this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
// 初始化类型 是 web 还是 reactor
this.webApplicationType = WebApplicationType.deduceFromClasspath();
// 从类路径下找到META‐INF/spring.factories文件中,加载ApplicationContextInitializer接口的实现类, 并设置
setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
// 从类路径下找到META‐INF/spring.factories文件中,ApplicationListener接口的实现类,并设置
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
this.mainApplicationClass = deduceMainApplicationClass();
}
ApplicationContextInitializer
定义
Spring 容器刷新之前,初始化 ConfigurableApplicationContext 上下文的回调接口 ApplicationContextInitializer 是 Spring 框架原有的产物
实现类
# 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.rsocket.context.RSocketPortInfoApplicationContextInitializer,\
org.springframework.boot.web.context.ServerPortInfoApplicationContextInitializer
ApplicationListener
定义
ApplicationListener:监听 spring 容器中发布的事件
实现类
# Application Listeners
org.springframework.context.ApplicationListener=\
org.springframework.boot.ClearCachesApplicationListener,\
org.springframework.boot.builder.ParentContextCloserApplicationListener,\
org.springframework.boot.cloud.CloudFoundryVcapEnvironmentPostProcessor,\
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.context.logging.ClasspathLoggingApplicationListener,\
org.springframework.boot.context.logging.LoggingApplicationListener,\
org.springframework.boot.liquibase.LiquibaseServiceLocatorApplicationListener
核心的运行方法
// 运行springboot应用, 创建并且刷新ApplicationContext.
public ConfigurableApplicationContext run(String... args) {
// 1.计时器 非重点
StopWatch stopWatch = new StopWatch();
stopWatch.start();
ConfigurableApplicationContext context = null;
// 2.支持报告spring应用启动错误 非重点
Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
configureHeadlessProperty();
// 3.获取listener 重点
SpringApplicationRunListeners listeners = getRunListeners(args);
// 3.1 调用启动中事件的方法 重点
listeners.starting();
try {
// 4. ApplicationArguments 重点
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
// 5. 预处理环境参数 重点
ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);
configureIgnoreBeanInfo(environment);
// 6. 打印Banner 非重点
Banner printedBanner = printBanner(environment);
// 7.创建ApplicationContext
context = createApplicationContext();
// 8.通过spi获取错误报告类 非重点
exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class,
new Class[] { ConfigurableApplicationContext.class }, context);
// 9. 预处理上下文 重点
prepareContext(context, environment, listeners, applicationArguments, printedBanner);
// 10. 刷新上下文 重点
refreshContext(context);
// 11. 后置处理 重点
afterRefresh(context, applicationArguments);
// 12. 计时器处理 非重点
stopWatch.stop();
if (this.logStartupInfo) {
new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch);
}
// 13. 调用启动事件的方法 重点
listeners.started(context);
// 14. 调用实现ApplicationRunner和CommandLineRunner的方法 重点
callRunners(context, applicationArguments);
}
catch (Throwable ex) {
// 15.异常处理 重点
handleRunFailure(context, ex, exceptionReporters, listeners);
throw new IllegalStateException(ex);
}
try {
// 16. 调用运行中事件 重点
listeners.running(context);
}
catch (Throwable ex) {
// 17 异常处理 重点
handleRunFailure(context, ex, exceptionReporters, null);
throw new IllegalStateException(ex);
}
return context;
}
解释 3.获取事件监听
private SpringApplicationRunListeners getRunListeners(String[] args) {
Class<?>[] types = new Class<?>[] { SpringApplication.class, String[].class };
return new SpringApplicationRunListeners(logger,
getSpringFactoriesInstances(SpringApplicationRunListener.class, types, this, args));
}
注:通过 SPI 加载 SpringApplicationRunListener 接口的所有实现
SpringApplicationRunListener 生命周期
定义
spring 应用运行方法的收听者
7 个阶段
default void starting() {
}
default void environmentPrepared(ConfigurableEnvironment environment) {
}
default void contextPrepared(ConfigurableApplicationContext context) {
}
default void contextLoaded(ConfigurableApplicationContext context) {
}
default void started(ConfigurableApplicationContext context) {
}
default void running(ConfigurableApplicationContext context) {
}
default void failed(ConfigurableApplicationContext context, Throwable exception) {
}
实现类
在 spring.factories 文件定义了 SpringApplicationRunListener 的实现类
# Run Listeners
org.springframework.boot.SpringApplicationRunListener=\
org.springframework.boot.context.event.EventPublishingRunListener
EventPublishingRunListener 类的实现接口的七个阶段
@Override
public void starting() {
// 广播开始的事件
this.initialMulticaster.multicastEvent(new ApplicationStartingEvent(this.application, this.args));
}
@Override
public void environmentPrepared(ConfigurableEnvironment environment) {
this.initialMulticaster
.multicastEvent(new ApplicationEnvironmentPreparedEvent(this.application, this.args, environment));
}
@Override
public void contextPrepared(ConfigurableApplicationContext context) {
this.initialMulticaster
.multicastEvent(new ApplicationContextInitializedEvent(this.application, this.args, context));
}
@Override
public void contextLoaded(ConfigurableApplicationContext context) {
for (ApplicationListener<?> listener : this.application.getListeners()) {
if (listener instanceof ApplicationContextAware) {
((ApplicationContextAware) listener).setApplicationContext(context);
}
context.addApplicationListener(listener);
}
this.initialMulticaster.multicastEvent(new ApplicationPreparedEvent(this.application, this.args, context));
}
@Override
public void started(ConfigurableApplicationContext context) {
context.publishEvent(new ApplicationStartedEvent(this.application, this.args, context));
}
@Override
public void running(ConfigurableApplicationContext context) {
context.publishEvent(new ApplicationReadyEvent(this.application, this.args, context));
}
@Override
public void failed(ConfigurableApplicationContext context, Throwable exception) {
ApplicationFailedEvent event = new ApplicationFailedEvent(this.application, this.args, context, exception);
if (context != null && context.isActive()) {
// Listeners have been registered to the application context so we should
// use it at this point if we can
context.publishEvent(event);
}
else {
// An inactive context may not have a multicaster so we use our multicaster to
// call all of the context's listeners instead
if (context instanceof AbstractApplicationContext) {
for (ApplicationListener<?> listener : ((AbstractApplicationContext) context)
.getApplicationListeners()) {
this.initialMulticaster.addApplicationListener(listener);
}
}
this.initialMulticaster.setErrorHandler(new LoggingErrorHandler());
this.initialMulticaster.multicastEvent(event);
}
}
注:EventPublishingRunListener 类的实现其实就是在不同阶段广播不同的事件
CommandLineRunner
定义
属于 springboot 应用的扩展点,在 springboot 应用的 applicationContext 初始化后开始被执行的
@FunctionalInterface
public interface CommandLineRunner {
/**
* Callback used to run the bean.
* @param args incoming main method arguments
* @throws Exception on error
*/
void run(String... args) throws Exception;
}
ApplicationRunner
定义
@FunctionalInterface
public interface ApplicationRunner {
/**
* Callback used to run the bean.
* @param args incoming application arguments
* @throws Exception on error
*/
void run(ApplicationArguments args) throws Exception;
}
构建 ApplicationArguments
public interface ApplicationArguments {
String[] getSourceArgs();
Set<String> getOptionNames();
boolean containsOption(String name);
List<String> getOptionValues(String name);
List<String> getNonOptionArgs();
}
public class DefaultApplicationArguments implements ApplicationArguments {
private final Source source;
private final String[] args;
public DefaultApplicationArguments(String... args) {
Assert.notNull(args, "Args must not be null");
this.source = new Source(args);
this.args = args;
}
......
private static class Source extends SimpleCommandLinePropertySource {
Source(String[] args) {
super(args);
}
}
}
创建 ApplicationContext
public static final String DEFAULT_CONTEXT_CLASS = "org.springframework.context."
+ "annotation.AnnotationConfigApplicationContext";
public static final String DEFAULT_SERVLET_WEB_CONTEXT_CLASS = "org.springframework.boot."
+ "web.servlet.context.AnnotationConfigServletWebServerApplicationContext";
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);
}
注:
这个比较简单,就是通过 org.springframework.boot.WebApplicationType 创建不同的 ApplicationContext
预处理上下文(prepareContext 方法)
private void prepareContext(ConfigurableApplicationContext context, ConfigurableEnvironment environment,
SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments, Banner printedBanner) {
// 设置容器的变量
context.setEnvironment(environment);
// 执行容器的后置处理
postProcessApplicationContext(context);
// 在上下文刷新之前,将ApplicationContextInitializer应用到上下文中。
applyInitializers(context);
// 广播上下文已经准备好的事件
listeners.contextPrepared(context);
if (this.logStartupInfo) {
logStartupInfo(context.getParent() == null);
logStartupProfileInfo(context);
}
// Add boot specific singleton beans
// 在容器中注入applicationArguments 的bean
ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
beanFactory.registerSingleton("springApplicationArguments", applicationArguments);
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");
// 加载我们的启动类,将启动类注入容器
load(context, sources.toArray(new Object[0]));
// 广播容器已加载的事件
listeners.contextLoaded(context);
}
刷新上下文
private void refreshContext(ConfigurableApplicationContext context) {
if (this.registerShutdownHook) {
try {
// 注册容器关闭之前做一些资源回收的操作
context.registerShutdownHook();
}
catch (AccessControlException ex) {
// Not allowed in some environments.
}
}
refresh(context);
}
真正调用 AbstractApplicationContext#refresh
protected void refresh(ApplicationContext applicationContext) {
Assert.isInstanceOf(AbstractApplicationContext.class, applicationContext);
((AbstractApplicationContext) applicationContext).refresh();
}
AbstractApplicationContext#refresh 这个方法主要是 spring 应用上下文生命周期的方法,这里只做简单的介绍,不往深处深究了
public void refresh() throws BeansException, IllegalStateException {synchronized (this.startupShutdownMonitor) {// 留给子类去实现创建 BeanFactory.ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// 预处理BeanFactory对象
prepareBeanFactory(beanFactory);
try {
// 允许子类中对BeanFactory进行后期处理.
postProcessBeanFactory(beanFactory);
// I调用注册为BeanFactory的工厂处理器
invokeBeanFactoryPostProcessors(beanFactory);
// 注册实现BeanPostProcessor接口的bean后置处理类
registerBeanPostProcessors(beanFactory);
// 初始化application实现广播器
initApplicationEventMulticaster();
// 又是留给子类实现刷新操作额
onRefresh();
// 检查bean的监听器并注册它们。.
registerListeners();
//完成Bean的初始化
finishBeanFactoryInitialization(beanFactory);
// 发布上下文刷新完成的时间
finishRefresh();
}catch (BeansException ex) {
// Propagate exception to caller.
throw ex;
}finally {
resetCommonCaches();
}
}
}
后置处理
protected void afterRefresh(ConfigurableApplicationContext context, ApplicationArguments args) {
}
这里是空方法,需要子类自己实现
调用启动事件的方法
void started(ConfigurableApplicationContext context) {
for (SpringApplicationRunListener listener : this.listeners) {
listener.started(context);
}
}
调用实现 ApplicationRunner 和 CommandLineRunner 的方法
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);
}
}
}
总结
运用了观察者模式
运用 SPI 技术来动态加载具体的实现类,dubbo 也是这样实现的,想了解 dubbo 的 spi 可以查看下面文章:Dubbo的SPI
SpringBoot 启动加载器有两种方式:CommandLineRunner 和 ApplicationRunner,并且是在应用程序启动完成后
CommandLineRunner 和 ApplicationRunner 的执行顺序,是将他们都统一添加到同一个 list 然后根据 @Order 注解派去
![用户头像](http://static001.geekbang.org/account/avatar/00/0f/f7/72/e7bc6ff1.jpg?x-oss-process=image/resize,w_200,h_200)
零点999
还未添加个人签名 2018.01.19 加入
还未添加个人简介
评论