几个重要的事件回调机制
ApplicationContextInitializer、SpringApplicationRunListener(配置在META-INF/spring.factories)
ApplicationRunner、CommandLineRunner(只需要放在ioc容器中)
启动流程
1、创建SpringApplication对象
- this.setInitializers(this.getSpringFactoriesInstances(ApplicationContextInitializer.class)):从类路径下找到META-INF/spring.factories配置的所有ApplicationContextInitializer
- this.setListeners(this.getSpringFactoriesInstances(ApplicationListener.class)):从类路径下找到META-INF/spring.factories配置的所有ApplicationListener
- this.mainApplicationClass = this.deduceMainApplicationClass():从多个配置类中找到有main方法的主配置类
@SpringBootApplication
@EnableDiscoveryClient
@EnableTransactionManagement // 开启事务
@MapperScan("com.ww.ideaapp.coupon.dao")
public class IdeaCouponApplication {
public static void main(String[] args) {
SpringApplication.run(IdeaCouponApplication.class, args);
}
}
public static ConfigurableApplicationContext run(Class<?> primarySource, String... args) {
return run(new Class[]{primarySource}, args);
}
public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {
return (new SpringApplication(primarySources)).run(args);
}
public SpringApplication(Class... primarySources) {
this((ResourceLoader)null, primarySources);
}
public SpringApplication(ResourceLoader resourceLoader, Class... primarySources) {
this.sources = new LinkedHashSet();
this.bannerMode = Mode.CONSOLE;
this.logStartupInfo = true;
this.addCommandLineProperties = true;
this.addConversionService = true;
this.headless = true;
this.registerShutdownHook = true;
this.additionalProfiles = new HashSet();
this.isCustomEnvironment = false;
this.lazyInitialization = false;
this.resourceLoader = resourceLoader;
Assert.notNull(primarySources, "PrimarySources must not be null");
this.primarySources = new LinkedHashSet(Arrays.asList(primarySources));
this.webApplicationType = WebApplicationType.deduceFromClasspath();
this.setInitializers(this.getSpringFactoriesInstances(ApplicationContextInitializer.class)); //从类路径下找到META-INF/spring.factories配置的所有ApplicationContextInitializer;然后保存起来
this.setListeners(this.getSpringFactoriesInstances(ApplicationListener.class)); //从类路径下找到META-INF/spring.factories配置的所有ApplicationListener
this.mainApplicationClass = this.deduceMainApplicationClass(); //从多个配置类中找到有main方法的主配置类
}
2、运行run方法
- 创建 StopWatch (StopWatch 主要用于简单统计 run 启动过程的时长)对象,并启动。
- 准备异常报告器:Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList();
- 设置系统属性 java.awt.headless,这里设置为 true,表示运行在服务器端,在没有显示器和鼠标键盘的模式下工作,模拟输入输出设备功能:this.configureHeadlessProperty();
- 从类路径下 META-INF/spring.factories 获取SpringApplicationRunListeners:SpringApplicationRunListeners listeners = this.getRunListeners(args);
- 调用所有的获取SpringApplicationRunListener.starting()方法:listeners.starting();
- 封装命令行参数:ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
- 准备环境:ConfigurableEnvironment environment = this.prepareEnvironment(listeners, applicationArguments);
- 环境准备完成:SpringApplicationRunListener.environmentPrepared();
- 打印控制台:Banner printedBanner = this.printBanner(environment);
- 创建 ApplicationContext;决定创建 web 的 ioc 还是普通的 ioc:context = this.createApplicationContext();
- 准备上下文环境,将environment保存到ioc中,而且applyInitializers();
applyInitializers():回调之前保存的所有的ApplicationContextInitializer的initialize方法,回调所有的SpringApplicationRunListener的contextPrepared():this.prepareContext(context, environment, listeners, applicationArguments, printedBanner); - 刷新容器,ioc容器初始化(如果是web应用还会创建嵌入式的Tomcat)。Spring注解版
扫描,创建,加载所有组件的地方(配置类,组件,自动配置):this.refreshContext(context); - 再一次刷新应用上下文,表示上下文被刷新后调用,这是一个空方法,主要是为做一些上下刷新后的拓展备用:this.afterRefresh(context, applicationArguments);
- 停止计时:stopWatch.stop();
- 输出日志记录执行主类名、时间信息。 if (this.logStartupInfo) {
(new StartupInfoLogger(this.mainApplicationClass)).logStarted(this.getApplicationLog(), stopWatch);
} - 发布应用上下文启动完成事件:listeners.started(context);
- 从ioc容器中获取所有的ApplicationRunner和CommandLineRunner进行回调ApplicationRunner先回调,CommandLineRunner再回调:this.callRunners(context, applicationArguments);
- 发布应用上下文就绪事件:listeners.running(context);
- 整个SpringBoot应用启动完成以后返回启动的ioc容器:return context;
public ConfigurableApplicationContext run(String... args) {
StopWatch stopWatch = new StopWatch();
stopWatch.start();
ConfigurableApplicationContext context = null; // IOC容器
// 准备异常报告器
Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList();
this.configureHeadlessProperty();
SpringApplicationRunListeners listeners = this.getRunListeners(args); //获取SpringApplicationRunListeners;从类路径下META-INF/spring.factories
listeners.starting(); //回调所有的获取SpringApplicationRunListener.starting()方法
Collection exceptionReporters;
try {
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args); //封装命令行参数
ConfigurableEnvironment environment = this.prepareEnvironment(listeners, applicationArguments); //准备环境,创建环境完成后回调
SpringApplicationRunListener.environmentPrepared();// 表示环境准备完成
this.configureIgnoreBeanInfo(environment);
Banner printedBanner = this.printBanner(environment); // 打印控制台
context = this.createApplicationContext(); //创建ApplicationContext;决定创建web的ioc还是普通的ioc
exceptionReporters = this.getSpringFactoriesInstances(SpringBootExceptionReporter.class, new Class[]{ConfigurableApplicationContext.class}, context);
/**
* 准备上下文环境;将environment保存到ioc中;而且applyInitializers();
* applyInitializers():回调之前保存的所有的ApplicationContextInitializer的initialize方法
* 回调所有的SpringApplicationRunListener的contextPrepared();
*/
this.prepareContext(context, environment, listeners, applicationArguments, printedBanner); //prepareContext运行完成以后回调所有的SpringApplicationRunListener的contextLoaded();
/**
* 刷新容器;ioc容器初始化(如果是web应用还会创建嵌入式的Tomcat);Spring注解版
* 扫描,创建,加载所有组件的地方;(配置类,组件,自动配置)
*/
this.refreshContext(context);
/**
* 再一次刷新应用上下文,表示上下文被刷新后调用,这是一个空方法,主要是为做一些上下刷新后的拓展备用
*/
this.afterRefresh(context, applicationArguments);
stopWatch.stop();
// 输出日志记录执行主类名、时间信息
if (this.logStartupInfo) {
(new StartupInfoLogger(this.mainApplicationClass)).logStarted(this.getApplicationLog(), stopWatch);
}
// 发布应用上下文启动完成事件
listeners.started(context);
/**
* 从ioc容器中获取所有的ApplicationRunner和CommandLineRunner进行回调
* ApplicationRunner先回调,CommandLineRunner再回调
*/
this.callRunners(context, applicationArguments);
} catch (Throwable var10) {
this.handleRunFailure(context, var10, exceptionReporters, listeners);
throw new IllegalStateException(var10);
}
try {
// 发布应用上下文就绪事件
listeners.running(context);
return context; //整个SpringBoot应用启动完成以后返回启动的ioc容器;
} catch (Throwable var9) {
this.handleRunFailure(context, var9, exceptionReporters, (SpringApplicationRunListeners)null);
throw new IllegalStateException(var9);
}
}
/**
* 准备上下文环境;将environment保存到ioc中;而且applyInitializers();
* applyInitializers():回调之前保存的所有的ApplicationContextInitializer的initialize方法
* 回调所有的SpringApplicationRunListener的contextPrepared();
*/
private void prepareContext(ConfigurableApplicationContext context, ConfigurableEnvironment environment, SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments, Banner printedBanner) {
context.setEnvironment(environment);
this.postProcessApplicationContext(context);
this.applyInitializers(context);
listeners.contextPrepared(context);
if (this.logStartupInfo) {
this.logStartupInfo(context.getParent() == null);
this.logStartupProfileInfo(context);
}
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());
}
Set<Object> sources = this.getAllSources();
Assert.notEmpty(sources, "Sources must not be empty");
this.load(context, sources.toArray(new Object[0]));
listeners.contextLoaded(context);
}