spring boot 源码解析 启动流程
在面试过程中经常被问到过spring boot的启动流程,今天就翻一下源码整体看一下;
首先,新建一个启动类,可以看到是首先调用的SpringApplication的静态方法run
@SpringBootApplicationpublic class SourceReadApplillcation { public static void main(String[] args) { SpringApplication.run(SourceReadApplillcation.class,args); }}
- 这里传入启动类的class,然后调用SpringApplication的构造函数new一个实例,接着调用run方法;
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(null, primarySources);} @SuppressWarnings({ "unchecked", "rawtypes" })public SpringApplication(ResourceLoader resourceLoader, Class ... primarySources) { this.resourceLoader = resourceLoader; Assert.notNull(primarySources, "PrimarySources must not be null"); this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources)); //推断web应用类型; this.webApplicationType = WebApplicationType.deduceFromClasspath(); //设置初始化器,从META-INF/spring.factories读取ApplicationContextInitializer //配置的值,读取详情后续研究 setInitializers((Collection) getSpringFactoriesInstances( ApplicationContextInitializer.class)); //设置监听器,同上,读取ApplicationListener配置的值 setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class)); //设置应用main启动类 this.mainApplicationClass = deduceMainApplicationClass();}
负责启动SpringBoot的主要方法
public ConfigurableApplicationContext run(String... args) { //计时器,主要为了统计消耗时间 StopWatch stopWatch = new StopWatch(); stopWatch.start(); //初始化应用上下文和异常报告集合 ConfigurableApplicationContext context = null; CollectionexceptionReporters = new ArrayList<>(); //设置java.awt.headless模式为true onfigureHeadlessProperty(); //设置并启动META-INF/spring.factories下SpringApplicationRunListener配置的监听器 //这里为EventPublishingRunListener,会通过反射调用其构造函数进行初始化 //并将一开始设置的监听器保存到AbstractApplicationEventMulticaster的 //内部类ListenerRetriever中,详情后续 SpringApplicationRunListeners listeners = getRunListeners(args); //触发监听器开始启动事件 listeners.starting(); try { //初始化应用参数,例如启动设置的命令行参数等,可以通过这个类获取 ApplicationArguments applicationArguments = new DefaultApplicationArguments( args); //准备运行环境 ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments); configureIgnoreBeanInfo(environment); //打印banner Banner printedBanner = printBanner(environment); //创建上下文,Springboot默认为AnnotationConfigApplicationContext context = createApplicationContext(); //准备异常报告 exceptionReporters = getSpringFactoriesInstances( SpringBootExceptionReporter.class, new Class[] { ConfigurableApplicationContext.class }, context); //准备上下文 prepareContext(context, environment, listeners, applicationArguments, printedBanner); //刷新上下文 refreshContext(context); //上下文刷新后置处理(空方法) afterRefresh(context, applicationArguments); //计时统计结束 stopWatch.stop(); if (this.logStartupInfo) { new StartupInfoLogger(this.mainApplicationClass) .logStarted(getApplicationLog(), stopWatch); } //触发启动完成事件 listeners.started(context); 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;}
整个启动流程大体就是这样,先有一个整体的概念,其中实现细节很庞杂,后续逐一研究