引言
我们都知道SpringBoot是目前微服务比较流行的技术选型,它可以将工程打成war包的方式在tomcat进行启动,也可以打成jar包,直接对外提供服务。那我们就会好奇,它是怎么去启动服务的,同时是怎么去加载前端页面、js文件、配置文件以及class文件等等然后向外提供web服务的。带着一系列的疑问,一步步探究SpringBoot的启动原理。
- SpringBoot大致启动流程
- 源码跟踪分析
- 总结
1.SpringBoot大致启动流程如下图所示。
2.源码跟踪分析
(1)main函数为主程序入口,SpringApplication
调用run
方法来启动SpringBoot
服务。注解的含义在上一篇文章中进行了说明,这里不再赘述。
@SpringBootApplication(scanBasePackages = {"com.hikvision.center"}) @MapperScan("com.hikvision.center.module.mapper") @ImportResource(locations = {"classpath:springMVC-servlet.xml"}) @ServletComponentScan public class WebApplication extends SpringBootServletInitializer{ static Logger logger = LoggerFactory.getLogger(WebApplication.class); public static void main(String[] args) { //程序入口 SpringApplication.run(WebApplication.class, args); } }
(2)run
方法是一个静态方法,主要执行一系列的初始化加载操作。
// public static ConfigurableApplicationContext run(Object source, String... args) { return run(new Object[] { source }, args); }
(3)ConfigurableApplicationContext
表示该 Context
是可修改的,也就是在构建 Context
中用户可以动态添加或修改已有的配置信息。下图为ApplicationContext
类关系图。
//创建了SpringApplication实例,同时调用run方法 public static ConfigurableApplicationContext run(Object[] sources, String[] args) { return new SpringApplication(sources).run(args); }
(4)初始化操作。
//SpringApplication构造函数中,进行初始化操作,上下文从指定的源中加载bean,实例可以在被调用前进行自定义 public SpringApplication(Object... sources) { initialize(sources); }
(5)主要是为SpringApplication对象赋一些初值。
@SuppressWarnings({ "unchecked", "rawtypes" }) private void initialize(Object[] sources) { if (sources != null && sources.length > 0) { this.sources.addAll(Arrays.asList(sources)); } //判断当前允许的环境是否为web环境 this.webEnvironment = deduceWebEnvironment(); // setInitializers((Collection) getSpringFactoriesInstances( ApplicationContextInitializer.class)); // setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class)); // this.mainApplicationClass = deduceMainApplicationClass(); }
(6)回到run
方法中去看具体的实现,该方法主要完成ApplicationContext
配置加载。
public ConfigurableApplicationContext run(String... args) { //性能检查,查看代码的运行时间 StopWatch stopWatch = new StopWatch(); stopWatch.start(); //设置上下文ID,设置父应用上下文,添加监听器和刷新容器相关的操作等 ConfigurableApplicationContext context = null; //异常分析器 FailureAnalyzers analyzers = null; //设置java.awt.headless属性, configureHeadlessProperty(); //创建应用监听器SpringApplicationRunListeners同时开始监听 SpringApplicationRunListeners listeners = getRunListeners(args); //启动监听器 listeners.started(); try { //获取启动参数 ApplicationArguments applicationArguments = new DefaultApplicationArguments( args); //加下SpringBoot配置环境 ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments); //定义输出的标志,打印spring Banner printedBanner = printBanner(environment); //创建应用上下文 context = createApplicationContext(); //注册异常分析器 analyzers = new FailureAnalyzers(context); //为ApplicationContext加载environment,初始化IoC容器,调用SpringApplicationRunListener的contextLoaded()方法,完成IOC容器加载 prepareContext(context, environment, listeners, applicationArguments, printedBanner); //初始化自动配置 refreshContext(context); //SpringBoot完成ApplicationContext初始化 afterRefresh(context, applicationArguments); //广播已经完成初始化全部过程 listeners.finished(context, null); //关闭任务执行还见监听器 stopWatch.stop(); if (this.logStartupInfo) { new StartupInfoLogger(this.mainApplicationClass) .logStarted(getApplicationLog(), stopWatch); } return context; } catch (Throwable ex) { handleRunFailure(context, listeners, analyzers, ex); throw new IllegalStateException(ex); } }
3.总结
从以上Springboot启动过程来看,它主要创建了程序配置环境(environment)、事件监听(listeners)、应用上下文(applicationContext),并在以上基础上,在容器中开始加载和实例化我们需要的Bean,在这些过程中有些过程是可以自定义的。