springboot启动分析
一、启动类
@SpringBootApplication
public class SpringBootStudyApplication {
public static void main(String[] args) {
// spring boot 启动入口
SpringApplication.run(SpringBootStudyApplication.class, args);
}
}
二、实例化SpringApplication对象
// org.springframework.boot.SpringApplication.SpringApplication
// SpringApplication的静态run方法,进入重载方法run
public static ConfigurableApplicationContext run(Class<?> primarySource,
String... args) {
return run(new Class<?>[] { primarySource }, args);
}
// 实例化SpringApplication对象,然后调用成员方法run(args)
public static ConfigurableApplicationContext run(Class<?>[] primarySources,
String[] args) {
return new SpringApplication(primarySources).run(args);
}
// 进入构造器重载方法
public SpringApplication(Class<?>... primarySources) {
this(null, primarySources);
}
// 实例化SpringApplication
@SuppressWarnings({ "unchecked", "rawtypes" })
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
this.resourceLoader = resourceLoader;
Assert.notNull(primarySources, "PrimarySources must not be null");
// 将配置的class保存起来
this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
// 自动推断出webApplication容器的类型(servlet)
this.webApplicationType = WebApplicationType.deduceFromClasspath();
// 从META-INF/spring.factories文件中读取ApplicationContextInitializer实现类,并且实例化(ApplicationContextInitializer接口在spring-context包下,只有一个抽象方法,可以在spring容器refresh刷新前进行一些其他操作)
setInitializers((Collection) getSpringFactoriesInstances(
ApplicationContextInitializer.class));
// 从META-INF/spring.factories文件中读取ApplicationListener实现类
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
// 从参数primarySources数组中推断出存在main方法的class
this.mainApplicationClass = deduceMainApplicationClass();
}
三、调用SpringApplication的run(args)方法
AbstractApplicationContext.refresh()分析
/**
* 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 context = null;
Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
configureHeadlessProperty();
// 从META-INF/spring.factories文件中获取SpringApplicationRunListener实现类,并且实例化
//(SpringApplicationRunListener实现类必须要有一个带参的构造器,参数列表是:SpringApplication application, String[] args),
// listeners保存了SpringApplicationRunListener集合
SpringApplicationRunListeners listeners = getRunListeners(args);
// 该方法其实调用的是遍历SpringApplicationRunListener的同名方法starting()
listeners.starting();
try {
ApplicationArguments applicationArguments = new DefaultApplicationArguments(
args);
// 准备配置环境
ConfigurableEnvironment environment = prepareEnvironment(listeners,
applicationArguments);
// 忽视一些bean类
configureIgnoreBeanInfo(environment);
// 打印banner图标
Banner printedBanner = printBanner(environment);
// 根据前面构造器方法中推断出的容器类型来创建ApplicationContext容器
context = createApplicationContext();
// 从spring.factories文件中获取异常报告器,根据参数进行实例化
exceptionReporters = getSpringFactoriesInstances(
SpringBootExceptionReporter.class,
new Class[] { ConfigurableApplicationContext.class }, context);
// 准备context容器,会调用ApplicationContextInitializer实现类的initial方法
prepareContext(context, environment, listeners, applicationArguments,
printedBanner);
// 会调用AbstractApplicationContext的refresh()方法
refreshContext(context);
// 容器刷新后处理,默认空方法,让子类进行实现
afterRefresh(context, applicationArguments);
// 统计运行的时间,进行打印日志
stopWatch.stop();
if (this.logStartupInfo) {
new StartupInfoLogger(this.mainApplicationClass)
.logStarted(getApplicationLog(), stopWatch);
}
// 遍历调用SpringApplicationRunListener的started(context)方法
listeners.started(context);
// 调用ApplicationRunner和CommandLineRunner的run方法
callRunners(context, applicationArguments);
}
catch (Throwable ex) {
handleRunFailure(context, ex, exceptionReporters, listeners);
throw new IllegalStateException(ex);
}
try {
// 遍历调用SpringApplicationRunListener的started(context)方法
listeners.running(context);
}
catch (Throwable ex) {
handleRunFailure(context, ex, exceptionReporters, null);
throw new IllegalStateException(ex);
}
return context;
}