Springboot提高了开发效率,简化了配置,往往使用一些注解就可以使项目跑起来,下面理一下Springboot的启动流程。Springboot版本:2.2.4.RELEASE
以下是一个常见的Springboot启动程序。
main方法里调用了SpringbootApplication的run方法。让我们点进去run方法,看看做了什么。
可以看到new了一个SpringApplication对象,然后调用其run方法。我们分两步来说即new SpringApplication(primarySources) 和 run(args).
从上图中可以看到主要是设置一些参数,其中主要重点讲一下这四块
// 获取 webApplicationType 有 REACTIVE 和 SERVLET
this.webApplicationType = WebApplicationType.deduceFromClasspath();
// 设置ApplicationContextInitializer
this.setInitializers(this.getSpringFactoriesInstances(ApplicationContextInitializer.class));
// 设置ApplicationListener
this.setListeners(this.getSpringFactoriesInstances(ApplicationListener.class));
// 获取MainApplication的Class
this.mainApplicationClass = this.deduceMainApplicationClass();
这里我们重点说this.getSpringFactoriesInstances()这个方法,这个其实使获取META-INF\spring.factories中的配置。
以this.getSpringFactoriesInstances(ApplicationContextInitializer.class)为例。
以上是获取到的实现类,点进去SpringFactoriesLoader.loadFactoryNames(type, classLoader)可以发现是读取的"META-INF/spring.factories"配置文件,如下
然后通过反射实例化这些instances.
public ConfigurableApplicationContext run(String... args) {
// 创建一个StopWatch并执行start方法,主要记录任务的执行时间
StopWatch stopWatch = new StopWatch();
stopWatch.start();
ConfigurableApplicationContext context = null;
Collection exceptionReporters = new ArrayList();
this.configureHeadlessProperty();
// 获取监听器(SpringApplicationRunListener实现类)类似以上,也是调用this.getSpringFactoriesInstances().
// 主要发布SpringApplicationEvent
SpringApplicationRunListeners listeners = this.getRunListeners(args);
// 监听器启动
listeners.starting();
Collection exceptionReporters;
try {
// 把输入参数转成DefaultApplicationArguments类
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
// 准备环境,在这里读取配置文件(application.properties application.yml)
ConfigurableEnvironment environment = this.prepareEnvironment(listeners, applicationArguments);
this.configureIgnoreBeanInfo(environment);
// 读取打印banner
Banner printedBanner = this.printBanner(environment);
// 创建应用程序上下文 此处创建了beanfactory
context = this.createApplicationContext();
// 获取SpringBootExceptionReporter的实现类对象
exceptionReporters = this.getSpringFactoriesInstances(SpringBootExceptionReporter.class, new Class[]{ConfigurableApplicationContext.class}, context);
// 准备上下文
this.prepareContext(context, environment, listeners, applicationArguments, printedBanner);
// 刷新上下文
this.refreshContext(context);
this.afterRefresh(context, applicationArguments);
stopWatch.stop();
if (this.logStartupInfo) {
(new StartupInfoLogger(this.mainApplicationClass)).logStarted(this.getApplicationLog(), stopWatch);
}
// 启动完成通知
listeners.started(context);
this.callRunners(context, applicationArguments);
} catch (Throwable var10) {
this.handleRunFailure(context, var10, exceptionReporters, listeners);
throw new IllegalStateException(var10);
}
try {
listeners.running(context);
return context;
} catch (Throwable var9) {
this.handleRunFailure(context, var9, exceptionReporters, (SpringApplicationRunListeners)null);
throw new IllegalStateException(var9);
}
}
private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments) {
// 根据webApplicationType返回ConfigurableEnvironment实例
ConfigurableEnvironment environment = this.getOrCreateEnvironment();
this.configureEnvironment((ConfigurableEnvironment)environment, applicationArguments.getSourceArgs());
ConfigurationPropertySources.attach((Environment)environment);
// 这里会创建一个ApplicationEnvironmentPreparedEvent类型的事件,并广播出去
// 之前获取的监听会监听到这个事件,并调用onApplicationEvent进行相应的处理
// ConfigFileApplicationListener监听器会加载配置文件(application.yml application.properties)
listeners.environmentPrepared((ConfigurableEnvironment)environment);
this.bindToSpringApplication((ConfigurableEnvironment)environment);
if (!this.isCustomEnvironment) {
environment = (new EnvironmentConverter(this.getClassLoader())).convertEnvironmentIfNecessary((ConfigurableEnvironment)environment, this.deduceEnvironmentClass());
}
ConfigurationPropertySources.attach((Environment)environment);
return (ConfigurableEnvironment)environment;
}
这里讲一下加载配置文件的流程。
涉及到的监听器和后置处理器如下
org.springframework.boot.context.config.ConfigFileApplicationListener
org.springframework.boot.env.YamlPropertySourceLoader
org.springframework.boot.env.PropertiesPropertySourceLoader
有兴趣的同学可以调试一下
根据webApplicationType创建ConfigurableApplicationContext实例
private void prepareContext(ConfigurableApplicationContext context, ConfigurableEnvironment environment, SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments, Banner printedBanner) {
// 设置上下文的配置环境
context.setEnvironment(environment);
// 上下文后置处理
this.postProcessApplicationContext(context);
//
this.applyInitializers(context);
// 以上为上下文准备阶段
// 以下为上下文加载阶段
// //通知监听器 context 准备完成,发布ApplicationContextInitializedEvent事件
listeners.contextPrepared(context);
// 打印启动日志和profile
if (this.logStartupInfo) {
this.logStartupInfo(context.getParent() == null);
this.logStartupProfileInfo(context);
}
// 获得 beanFactory 并注册单例
ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
beanFactory.registerSingleton("springApplicationArguments", applicationArguments);
if (printedBanner != null) {
// 注册打印banner对象
beanFactory.registerSingleton("springBootBanner", printedBanner);
}
// 设置是否允许覆盖
if (beanFactory instanceof DefaultListableBeanFactory) {
((DefaultListableBeanFactory)beanFactory).setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
}
// 如果延迟加载,在上下文添加处理器
if (this.lazyInitialization) {
context.addBeanFactoryPostProcessor(new LazyInitializationBeanFactoryPostProcessor());
}
Set
public void refresh() throws BeansException, IllegalStateException {
synchronized(this.startupShutdownMonitor) {
// 为应用上下文的刷新做准备--设置时间、记录刷新日志、验证属性
this.prepareRefresh();
// 让子类刷新内部的bean factory
ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory();
// 准备在这个应用上下文中使用的bean factory
this.prepareBeanFactory(beanFactory);
try {
// bean factory 后置处理
this.postProcessBeanFactory(beanFactory);
// 调用应用上下文中作为bean注册的工厂处理器
this.invokeBeanFactoryPostProcessors(beanFactory);
// 注册创建bean的bean处理器,以增强 bean
this.registerBeanPostProcessors(beanFactory);
// 初始化消息源
this.initMessageSource();
// 初始化事件广播
this.initApplicationEventMulticaster();
// 此处定义特别的bean创建,一般是服务器有关或个性化对象
// 子这里会创建默认tomcat服务器
this.onRefresh();
// 注册监听器bean
this.registerListeners();
// 实例化所有的单例bean
this.finishBeanFactoryInitialization(beanFactory);
// 发布相应的事件
this.finishRefresh();
} catch (BeansException var9) {
if (this.logger.isWarnEnabled()) {
this.logger.warn("Exception encountered during context initialization - cancelling refresh attempt: " + var9);
}
this.destroyBeans();
this.cancelRefresh(var9);
throw var9;
} finally {
this.resetCommonCaches();
}
}
}
listeners.started(context);
listeners.running(context);
void started(ConfigurableApplicationContext context) {
Iterator var2 = this.listeners.iterator();
while(var2.hasNext()) {
SpringApplicationRunListener listener = (SpringApplicationRunListener)var2.next();
listener.started(context);
}
}
void running(ConfigurableApplicationContext context) {
Iterator var2 = this.listeners.iterator();
while(var2.hasNext()) {
SpringApplicationRunListener listener = (SpringApplicationRunListener)var2.next();
listener.running(context);
}
}
// 发布ApplicationStartedEvent事件
public void started(ConfigurableApplicationContext context) {
context.publishEvent(new ApplicationStartedEvent(this.application, this.args, context));
}
// 发布ApplicationReadyEvent事件
public void running(ConfigurableApplicationContext context) {
context.publishEvent(new ApplicationReadyEvent(this.application, this.args, context));
}
以上为自己理解,如有错误,请指出。