随着微服务的发展,springboot已经不可或缺,也许你会想为什么点击启动类就能启动整个服务,他们内部到底是怎么运作的,能够如此方便快捷,那么本文我们就来看看这个 SpringApplication 以及 run() 方法 是如何加载的,它背后又隐藏了哪些奥秘呢?
@SpringBootApplication
public class SpringCloud01Application {
public static void main(String[] args) {
/*SpringApplication sa=new SpringApplication(SpringCloud01Application.class);
sa.setInitializers();//用户自定义的扩展
sa.run(args);*/
SpringApplication.run(SpringCloud01Application.class, args);
}
}
一、SpringApplication实例的初始化
首先new SpringApplication()对象,内部有四步操作

四个关键的步骤已标注在图中,分别解释如下:
①deduceFromClasspath() 推断应用的类型:创建的是REACTIVE应用、SERVLET应用、NONE 三种中的某一种

②setInitializers 使用SpringFactoriesLoader
查找并加载classpath下META-INF/spring.factories
文件中所有可用的 ApplicationContextInitializer

③ setListeners使用SpringFactoriesLoader
查找并加载classpath下META-INF/spring.factories
文件中的所有可用的 ApplicationListener

④ 推断并设置main
方法的定义类

二、SpringApplication的run()方法探秘
整个方法的目的是创建 applicationcontext ,从该方法能看到, SpringApplicationRunListeners 监听了整个生命周期,主要包括几个核心方法,除此之外,一些扩展占据了加载applicationcontext生命周期的大半江山
/** * Run the Spring application, creating and refreshing a new * {@link ApplicationContext}. * @param args the application arguments (usually passed from a Java main method) * @return a running {@link ApplicationContext} */ public ConfigurableApplicationContext run(String... args) { StopWatch stopWatch = new StopWatch(); stopWatch.start(); DefaultBootstrapContext bootstrapContext = createBootstrapContext(); ConfigurableApplicationContext context = null; configureHeadlessProperty(); SpringApplicationRunListeners listeners = getRunListeners(args); listeners.starting(bootstrapContext, this.mainApplicationClass); try { ApplicationArguments applicationArguments = new DefaultApplicationArguments(args); ConfigurableEnvironment environment = prepareEnvironment(listeners, bootstrapContext, applicationArguments); configureIgnoreBeanInfo(environment); Banner printedBanner = printBanner(environment); context = createApplicationContext(); context.setApplicationStartup(this.applicationStartup); prepareContext(bootstrapContext, 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, listeners); throw new IllegalStateException(ex); } try { listeners.running(context); } catch (Throwable ex) { handleRunFailure(context, ex, null); throw new IllegalStateException(ex); } return context; }

我们将各步骤总结精炼如下:
- 通过
SpringFactoriesLoader
加载META-INF/spring.factories
文件,获取并创建SpringApplicationRunListener
对象 - 然后由
SpringApplicationRunListener
来发出starting
消息 - 创建参数,并配置当前
SpringBoot
应用将要使用的Environment
- 完成之后,依然由
SpringApplicationRunListener
来发出environmentPrepared
消息 - 创建
ApplicationContext
- 初始化
ApplicationContext
,并设置Environment
,加载相关配置等 - 由
SpringApplicationRunListener
来发出contextPrepared
消息,告知Spring Boot 应用使用的ApplicationContext
已准备OK - 将各种
beans
装载入ApplicationContext
,继续由SpringApplicationRunListener
来发出contextLoaded
消息,告知 Spring Boot 应用使用的ApplicationContext
已装填OK refresh ApplicationContext
,完成IoC容器可用的最后一步- 由
SpringApplicationRunListener
来发出started
消息 - 调用
callRunners(...)
方法,让实现了ApplicationRunner
和CommandLineRunner
接口类的run
方法得以执行,用于在 Spring 应用上下文准备完毕后,执行一些额外操作。从而完成最终的程序的启动。 - 由
SpringApplicationRunListener
来发出running
消息,告知程序已运行起来了
在Springboot揭秘 快速构建微服务体系一书中有如下图,说明了springboot的启动过程

Comments | NOTHING