说明: 以下使用的是 Spring Boot 2.0.4 版本
几个重要的事件回调机制
配置在META-INF/spring.factories
ApplicationContextInitializer
SpringApplicationRunListener
和放在ioc容器中
ApplicationRunner
CommandLineRunner
# Initializers
org.springframework.context.ApplicationContextInitializer=\
org.springframework.boot.autoconfigure.SharedMetadataReaderFactoryContextInitializer,\
org.springframework.boot.autoconfigure.logging.ConditionEvaluationReportLoggingListener
# Application Listeners
org.springframework.context.ApplicationListener=\
org.springframework.boot.autoconfigure.BackgroundPreinitializer
启动Spring Boot 项目
具体的启动流程可以从 SpringApplication.run()方法点进去,进一步查看源码
@SpringBootApplication
public class AdminCommonApplication {
public static void main(String[] args) {
SpringApplication.run(AdminCommonApplication.class, args);
}
}
创建 SpringApplication
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环境中的几个类,来决定webApplicationType 的类型
this.webApplicationType = deduceWebApplicationType();
// 从META-INF/spring.factories 下获取 ApplicationContextInitializer类型的子类
setInitializers((Collection) getSpringFactoriesInstances(
ApplicationContextInitializer.class));
// 从META-INF/spring.factories 下获取 ApplicationListener 类型的子类
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
this.mainApplicationClass = deduceMainApplicationClass();
}
SpringApplication运行run()方法
public ConfigurableApplicationContext run(String... args) {
StopWatch stopWatch = new StopWatch();
stopWatch.start();
ConfigurableApplicationContext context = null;
Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
configureHeadlessProperty();
// 从META-INF/spring.factories 下获取 SpringApplicationRunListeners 类型的子类
SpringApplicationRunListeners listeners = getRunListeners(args);
// 回调SpringApplicationRunListener的starting()方法
listeners.starting();
try {
// 包装命令行参数
ApplicationArguments applicationArguments = new DefaultApplicationArguments(
args);
// 准备环境,此方法中,创建环境完成后回调SpringApplicationRunListener.environmentPrepared();表示环境准
//备完成
ConfigurableEnvironment environment = prepareEnvironment(listeners,
applicationArguments);
configureIgnoreBeanInfo(environment);
// 打印 banner 图标
Banner printedBanner = printBanner(environment);
// 创建ApplicationContext,决定创建web的ioc还是普通的ioc
context = createApplicationContext();
exceptionReporters = getSpringFactoriesInstances(
SpringBootExceptionReporter.class,
new Class[] { ConfigurableApplicationContext.class }, context);
// 准备IOC容器,将environment 设置到ApplicationContext中
// 并回调所有ApplicationContextInitializer 的initialize()
// 再回调SpringApplicationRunListener的contextPrepared()方法
// 再回调SpringApplicationRunListener的contextLoaded()方法
prepareContext(context, environment, listeners, applicationArguments,
printedBanner);
//[spring 启动流程,参看另外几篇文章] 刷新容器ioc容器初始化(如果是web应用还会创建嵌入式的Tomcat)
// 扫描,创建,加载所有组件的地方;(配置类,组件,自动配置)
refreshContext(context);
// 这是一个空方法
afterRefresh(context, applicationArguments);
stopWatch.stop();
if (this.logStartupInfo) {
new StartupInfoLogger(this.mainApplicationClass)
.logStarted(getApplicationLog(), stopWatch);
}
// 再回调SpringApplicationRunListener的started()方法
listeners.started(context);
//从ioc容器中获取所有的ApplicationRunner和CommandLineRunner进行回调
//先回调ApplicationRunner.run()方法,再回调CommandLineRunner.run()方法
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 ConfigurableEnvironment prepareEnvironment(
SpringApplicationRunListeners listeners,
ApplicationArguments applicationArguments) {
// Create and configure the environment
ConfigurableEnvironment environment = getOrCreateEnvironment();
//配置环境,传入 environment 和命令行参数
//项目中的配置文件也是在此读取!
configureEnvironment(environment, applicationArguments.getSourceArgs());
// 回调SpringApplicationRunListener的environmentPrepared()方法
listeners.environmentPrepared(environment);
bindToSpringApplication(environment);
if (this.webApplicationType == WebApplicationType.NONE) {
environment = new EnvironmentConverter(getClassLoader())
.convertToStandardEnvironmentIfNecessary(environment);
}
ConfigurationPropertySources.attach(environment);
return environment;
}
准备IOC容器
private void prepareContext(ConfigurableApplicationContext context,
ConfigurableEnvironment environment, SpringApplicationRunListeners listeners,
ApplicationArguments applicationArguments, Banner printedBanner) {
//先将 environment 设置到 ApplicationContext 中
context.setEnvironment(environment);
postProcessApplicationContext(context);
//回调所有ApplicationContextInitializer 的initialize()
applyInitializers(context);
// 回调SpringApplicationRunListener的contextPrepared()方法
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 = getAllSources();
Assert.notEmpty(sources, "Sources must not be empty");
load(context, sources.toArray(new Object[0]));
// 回调SpringApplicationRunListener的contextLoaded()方法
listeners.contextLoaded(context);
}
回调 ApplicationContextInitializer 的initialize()方法
利用此性质,可以用来,从远程的配置中心拉取配置,并覆盖本地配置
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);
}
}
回调ApplicationRunner 和 CommandLineRunner 的run()方法
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);
}
}
}