昨天无意之间看到了一家公司对于springboot的面试题,自己回来之后也就翻了翻源码,做了一个小整理。
在翻源码之前我们先要了解几个类
ApplicationContextInitializer Context初始化后调用的类
SpringApplicationRunListener SpringBoot运行监听的类
ApplicationRunner
CommandLineRunner
上面这两个几乎可以等价,用于启动后做客户自定义的操作
首先我们先来定义几个类方便我们分析
新建java类CustomCommandLineRunner类
@Component
public class CustomCommandLineRunner implements CommandLineRunner {
@Override
public void run(String... args) throws Exception {
System.out.println("CustomCommandLineRunner.run()执行了"+ Arrays.asList(args));
}
}
新建java类CustomApplicationRunner
@Component
public class CustomApplicationRunner implements ApplicationRunner {
@Override
public void run(ApplicationArguments args) throws Exception {
System.out.println("CustomApplicationRunne.run()执行了");
}
}
新建java类CustomApplicationContextInitializer
public class CustomApplicationContextInitializer
implements ApplicationContextInitializer<ConfigurableApplicationContext> {
@Override
public void initialize(ConfigurableApplicationContext applicationContext) {
System.out.println("CustomApplicationContextInitializer.initialize()执行了"+applicationContext);
}
}
新建java类CustomSpringApplicationRunListener
public class CustomSpringApplicationRunListener implements SpringApplicationRunListener {
//必须有的构造器
public CustomSpringApplicationRunListener (SpringApplication application, String[] args){
}
@Override
public void starting() {
System.out.println("CustomSpringApplicationRunListener.starting()执行了");
}
@Override
public void environmentPrepared(ConfigurableEnvironment environment) {
System.out.println("CustomSpringApplicationRunListener.environmentPrepared()执行了");
}
@Override
public void contextPrepared(ConfigurableApplicationContext context) {
System.out.println("CustomSpringApplicationRunListener.contextPrepared()执行了");
}
@Override
public void contextLoaded(ConfigurableApplicationContext context) {
System.out.println("CustomSpringApplicationRunListener.contextLoaded()执行了");
}
@Override
public void started(ConfigurableApplicationContext context) {
System.out.println("CustomSpringApplicationRunListener.started()执行了");
}
@Override
public void running(ConfigurableApplicationContext context) {
System.out.println("CustomSpringApplicationRunListener.running()执行了");
}
@Override
public void failed(ConfigurableApplicationContext context, Throwable exception) {
System.out.println("CustomSpringApplicationRunListener.failed()执行了");
}
}
在resources/META-INF/spring.factories增加
org.springframework.context.ApplicationContextInitializer=\
com.naver.listener.CustomApplicationContextInitializer
org.springframework.boot.SpringApplicationRunListener=\
com.naver.listener.CustomSpringApplicationRunListener
为什么如此,后面源代码分析
我们跟踪SpringBoot的启动类
public static ConfigurableApplicationContext run(Class<?>[] primarySources,
String[] args) {
return new SpringApplication(primarySources).run(args);
}
其实SpringBoot启动就着两个步骤,先创建ConfigurableApplicationContext ,然后再调用Run方法。
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
this.resourceLoader = resourceLoader;
Assert.notNull(primarySources, "PrimarySources must not be null");
//保存主类
this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
//判断当前是什么类型项目
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();
}
可见着一步非常简单,只是把一些相关的类都加载了而已,并没执行
真的重要是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);
//准备环境
ConfigurableEnvironment environment = prepareEnvironment(listeners,
applicationArguments);
configureIgnoreBeanInfo(environment);
//创回调SpringApplicationRunListener.environmentPrepared();
//表示环境准备完成
//打印Banner
Banner printedBanner = printBanner(environment);
//根据环境创建context
context = createApplicationContext();
//错误的异常报表
exceptionReporters = getSpringFactoriesInstances(
SpringBootExceptionReporter.class,
new Class[] { ConfigurableApplicationContext.class }, context);
//准备上下文环境;
//将environment保存到ioc中;
//applyInitializers()调用所有的ApplicationContextInitializer的initialize方法
//调用所有的SpringApplicationRunListener的contextPrepared();
prepareContext(context, environment, listeners, applicationArguments,
printedBanner);
//SpringApplicationRunListener的contextLoaded
//刷新容器
//扫描,创建,加载所有组件;
refreshContext(context);
afterRefresh(context, applicationArguments);
stopWatch.stop();
if (this.logStartupInfo) {
new StartupInfoLogger(this.mainApplicationClass)
.logStarted(getApplicationLog(), stopWatch);
}
//所有的SpringApplicationRunListener回调started方法
listeners.started(context);
//获取所有的ApplicationRunner和CommandLineRunner进行调用
callRunners(context, applicationArguments);
}
catch (Throwable ex) {
handleRunFailure(context, ex, exceptionReporters, listeners);
throw new IllegalStateException(ex);
}
try {
//所有的SpringApplicationRunListener的running();
listeners.running(context);
}
catch (Throwable ex) {
handleRunFailure(context, ex, exceptionReporters, null);
throw new IllegalStateException(ex);
}
return context;
}