springboot启动流程源码分析
SpringApplication.run(MessageApplication.class, args);
springboot项目启动主入口如上所示。
/**
* Static helper that can be used to run a {@link SpringApplication} from the
* specified source using default settings.
* @param primarySource the primary source to load
* @param args the application arguments (usually passed from a Java main method)
* @return the running {@link ApplicationContext}
*/
public static ConfigurableApplicationContext run(Class<?> primarySource,
String... args) {
return run(new Class<?>[] { primarySource }, args);
}
一般来说这里是调用传入反射类实例构造方法,当着这里的反射的类实例也可以是数组形式,同时启动多个入口,启动顺序根据反射类数组的顺序决定。
首先来粗略的说是springboot的构造部分:
主要springboot启动的初始化方法
/**
* Create a new {@link SpringApplication} instance. The application context will load
* beans from the specified primary sources (see {@link SpringApplication class-level}
* documentation for details. The instance can be customized before calling
* {@link #run(String...)}.
* @param resourceLoader the resource loader to use
* @param primarySources the primary bean sources
* @see #run(Class, String[])
* @see #setSources(Set)
*/
@SuppressWarnings({ "unchecked", "rawtypes" })
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
// 这里是引入了资源加载器,
this.resourceLoader = resourceLoader;
Assert.notNull(primarySources, "PrimarySources must not be null");
//如果有多个主加载入口的话,会把它们转为一个linkedHashSet
this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
//设置应用的类型是servlet还是其他别的
this.webApplicationType = deduceWebApplicationType();
//从spring.factories中获取初始化应用需要的容器
setInitializers((Collection) getSpringFactoriesInstances(
ApplicationContextInitializer.class));
//从spring.factories中获取初始化应用需要的监听器
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
//已main方法作为程序的主入口
this.mainApplicationClass = deduceMainApplicationClass();
}
接下来我们实际上可以看到,构造完了之后执行了一个run方法
/**
* Static helper that can be used to run a {@link SpringApplication} from the
* specified sources using default settings and user supplied arguments.
* @param primarySources the primary sources to load
* @param args the application arguments (usually passed from a Java main method)
* @return the running {@link ApplicationContext}
*/
public static ConfigurableApplicationContext run(Class<?>[] primarySources,
String[] args) {
return new SpringApplication(primarySources).run(args);
}
接下来才是重头戏,spring开始创建和刷新应用上下文了。
/**
* Run the Spring application, creating and refreshing a new
* {@link ApplicationContext}.
* @param args the application arguments (usually passed from a Java main method)
* @return a running {@link ApplicationContext}
*/
public ConfigurableApplicationContext run(String... args) {
//首先这里初始化了一个类,就是一个记录任务花费时间的工具类,非线程安全
StopWatch stopWatch = new StopWatch();
stopWatch.start();
//ConfigurableApplicationContext声明,主要是提供一个需要上下的实现
ConfigurableApplicationContext context = null;
//这里是异常处理器
Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
configureHeadlessProperty();
//// 获取SpringApplicationRunListeners,内部只有一个EventPublishingRunListener
SpringApplicationRunListeners listeners = getRunListeners(args);
listeners.starting();
try {
ApplicationArguments applicationArguments = new DefaultApplicationArguments(
args);
ConfigurableEnvironment environment = prepareEnvironment(listeners,
applicationArguments);
//加载环境配置文件例如 bootstrap.yml
configureIgnoreBeanInfo(environment);
Banner printedBanner = printBanner(environment);
//创建应用上下文
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;
}
未完待续>>>
网友评论