SpringBoot启动分析
SpringBoot源码分析分为两部分:
- 加载所有starter类型得jar和配置文件
- 生成ApplicationContext,调用Spring中得refresh()方法
SpringBoot的运行原理是基于Spring的,所以熟悉Spring源码的人更能快速的理解SpringBoot的源码,下面开始分析。
SpringBoot的入口是SpringApplication中的run()方法,所以流程分为两部分:构造器部分和run()方法实际执行SpringIOC的部分。
- SpringApplication构造器源码分析(一)
构造器源代码如下:
/**
* 1.构造器主要是把确定当前应用的类型,比如当前应用是Servlet/REACTIVE/NONE
* 2.扫描所有的META-INF/spring.factories文件,找到对应的类,填充到属性中,
* 比如:在spring-boot-2.0.3.RELEASE.jar包中的META-INF/spring.factories文件中的ConfigFileApplicationListener类,
* 在onApplicationEvent()类中加载的用户配置文件
* @param resourceLoader
* @param primarySources
*/
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
this.resourceLoader = resourceLoader;
Assert.notNull(primarySources, "PrimarySources must not be null");
this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
//根据当前项目中包的配置找到当前项目环境:比如是SERVLET或者是REACTIVE或者就是一个jar
this.webApplicationType = deduceWebApplicationType();
//找到当前所有META-INF/spring.factories文件下(包括jar)下的所有实现了ApplicationContextInitializer接口的类,set到initializers属性中
setInitializers((Collection) getSpringFactoriesInstances(
ApplicationContextInitializer.class));
//找到当前所有META-INF/spring.factories文件下(包括jar)下的所有实现了ApplicationListener接口的类,set到listeners属性中
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
this.mainApplicationClass = deduceMainApplicationClass();
}
-
SpringApplication#run()方法分析(二)
public ConfigurableApplicationContext run(String... args) { //计时器 StopWatch stopWatch = new StopWatch(); stopWatch.start(); ConfigurableApplicationContext context = null; Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>(); configureHeadlessProperty(); //生成一个SpringApplication的监听器,专门监听启动过程 SpringApplicationRunListeners listeners = getRunListeners(args); //启动器开始 listeners.starting(); try { //启动参数封装 ApplicationArguments applicationArguments = new DefaultApplicationArguments( args); //创建一个Enviroment,处理激活文件 ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments); configureIgnoreBeanInfo(environment); //打印banner Banner printedBanner = printBanner(environment); //根据环境类型创建一个ApplicationContext,如果是Servlet的话,创建的是AnnotationConfigServletWebServerApplicationContext类 context = createApplicationContext(); exceptionReporters = getSpringFactoriesInstances( SpringBootExceptionReporter.class, new Class[] { ConfigurableApplicationContext.class }, context); /** * 1. 调用ApplicationContextInitializer类的initialize() * 2. 调用所有的ApplicationListener的onApplicationEvent()方法,此处为观察者模式,上文说的加载自己的配置文件就是在这里加载的,对应的 类为ConfigFileApplicationListener类 */ prepareContext(context, environment, listeners, applicationArguments, printedBanner); /** * 1.调用AbstractApplicationContext中的refresh方法,此处为即为SpringBoot的核心,也是Spring的核心,Spring的上下文都会调用到这里, * 2.在调用refresh方法的时候,会有一个onRefresh方法,调用到AnnotationConfigServletWebServerApplicationContext类的父类ServletWebServerApplicationContext中的onRefresh()方法,这里回根据 * 配置去加载对应的服务器。 */ refreshContext(context); afterRefresh(context, applicationArguments); stopWatch.stop(); if (this.logStartupInfo) { new StartupInfoLogger(this.mainApplicationClass) .logStarted(getApplicationLog(), stopWatch); } listeners.started(context); /** * 调用ApplicationRunner/CommandLineRunner的实现类,项目启动就会访问,在这里做一个项目启动的扩展。 */ 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; }
到此,SpringBoot的整个流程就结束了,但是还有很多东西没有写,比如@Configuration是怎么解析的,其实就跟Spring的流程有关系了,就会在ConfigurationClassPostProcessor类中解析,实现了BeanDefinitionRegistryPostProcessor接口,会在refresh()方法中执行,postProcessBeanDefinitionRegistry()方法…这些都是Spring的东西。至于SpringBoot,总结代码如下
以上就是对SpringBoot2.0.3源码的大致流程分析。