启动过程
1、springboot的入口程序
``java
@SpringBootApplicationpublic class StartupApplication { public static void main(String[] args) { SpringApplication.run(StartupApplication.class, args); }}
`
当程序开始执行之后-会调用SpringApplication的构造方法-进行某些初始参数的设置
`java
//创建一个新的实例-这个应用程序的上下文将要从指定的来源加载Beanpublic SpringApplication(ResourceLoader resourceLoader, Class... primarySources) { //资源初始化资源加载器-默认为null this.resourceLoader = resourceLoader; //断言主要加载资源类不能为 null-否则报错 Assert.notNull(primarySources, "PrimarySources must not be null"); //初始化主要加载资源类集合并去重 this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources)); //推断当前 WEB 应用类型-一共有三种:NONE,SERVLET,REACTIVE this.webApplicationType = WebApplicationType.deduceFromClasspath(); //设置应用上线文初始化器,从"META-INF/spring.factories"读取ApplicationContextInitializer类的实例名称集合并去重-并进行set去重。(一共7个) setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class)); //设置监听器,从"META-INF/spring.factories"读取ApplicationListener类的实例名称集合并去重-并进行set去重。(一共11个) setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class)); //推断主入口应用类-通过当前调用栈-获取Main方法所在类-并赋值给mainApplicationClass this.mainApplicationClass = deduceMainApplicationClass(); }
`
在上述构造方法中-有一个判断应用类型的方法-用来判断当前应用程序的类型:
`java
static WebApplicationType deduceFromClasspath() { if (ClassUtils.isPresent(WEBFLUX_INDICATOR_CLASS, null) && !ClassUtils.isPresent(WEBMVC_INDICATOR_CLASS, null) && !ClassUtils.isPresent(JERSEY_INDICATOR_CLASS, null)) { return WebApplicationType.REACTIVE; } for (String className : SERVLET_INDICATOR_CLASSES) { if (!ClassUtils.isPresent(className, null)) { return WebApplicationType.NONE; } } return WebApplicationType.SERVLET; }//WebApplicationType的类型public enum WebApplicationType { / * The application should not run as a web application and should not start an * embedded web server. * 非web项目 */ NONE, / * The application should run as a servlet-based web application and should start an * embedded servlet web server. * servlet web 项目 */ SERVLET, /** * The application should run as a reactive web application and should start an * embedded reactive web server. * 响应式 web 项目 */ REACTIVE;
`
springboot启动的运行方法-可以看到主要是各种运行环境的准备工作
`java
public ConfigurableApplicationContext run(String... args) { //1、创建并启动计时监控类 StopWatch stopWatch = new StopWatch(); stopWatch.start(); //2、初始化应用上下文和异常报告集合 ConfigurableApplicationContext context = null; Collection exceptionReporters = new ArrayList<>(); //3、设置系统属性“java.awt.headless”的值-默认为true-用于运行headless服务器-进行简单的图像处理-多用于在缺少显示屏、键盘或者鼠标时的系统配置-很多监控工具如jconsole 需要将该值设置为true configureHeadlessProperty(); //4、创建所有spring运行监听器并发布应用启动事件-简单说的话就是获取SpringApplicationRunListener类型的实例(EventPublishingRunListener对象)-并封装进SpringApplicationRunListeners对象-然后返回这个SpringApplicationRunListeners对象。说的再简单点-getRunListeners就是准备好了运行时监听器EventPublishingRunListener。 SpringApplicationRunListeners listeners = getRunListeners(args); listeners.starting(); try { //5、初始化默认应用参数类 ApplicationArguments applicationArguments = new DefaultApplicationArguments(args); //6、根据运行监听器和应用参数来准备spring环境 ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments); //将要忽略的bean的参数打开 configureIgnoreBeanInfo(environment); //7、创建banner打印类 Banner printedBanner = printBanner(environment); //8、创建应用上下文-可以理解为创建一个容器 context = createApplicationContext(); //9、准备异常报告器-用来支持报告关于启动的错误 exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class, new Class[] { ConfigurableApplicationContext.class }, context); //10、准备应用上下文-该步骤包含一个非常关键的操作-将启动类注入容器-为后续开启自动化提供基础 prepareContext(context, environment, listeners, applicationArguments, printedBanner); //11、刷新应用上下文 refreshContext(context); //12、应用上下文刷新后置处理-做一些扩展功能 afterRefresh(context, applicationArguments); //13、停止计时监控类 stopWatch.stop(); //14、输出日志记录执行主类名、时间信息 if (this.logStartupInfo) { new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch); } //15、发布应用上下文启动监听事件 listeners.started(context); //16、执行所有的Runner运行器 callRunners(context, applicationArguments); }catch (Throwable ex) { handleRunFailure(context, ex, exceptionReporters, listeners); throw new IllegalStateException(ex); } try { //17、发布应用上下文就绪事件 listeners.running(context); }catch (Throwable ex) { handleRunFailure(context, ex, exceptionReporters, null); throw new IllegalStateException(ex); } //18、返回应用上下文 return context;}
`
下面详细介绍各个启动的环节:
1、创建并启动计时监控类-可以看到记录当前任务的名称-默认是空字符串-然后记录当前springboot应用启动的开始时间。
`java
StopWatch stopWatch = new StopWatch();stopWatch.start();//详细源代码public void start() throws IllegalStateException { start("");}public void start(String taskName) thr