public ConfigurableApplicationContext run(String... args) { StopWatch stopWatch = new StopWatch(); //设置计时器 stopWatch.start(); //记录当前时间 ConfigurableApplicationContext context = null; configureHeadlessProperty(); //设置java.awt.headless为true或false SpringApplicationRunListeners listeners = getRunListeners(args);//获取事件发布器(控制所有事件的执行时机) listeners.started(); //事件发布器发布ApplicationStartedEvent事件,所有监听了该事件的ApplicationListener实现类执行逻辑 try { context = doRun(listeners, args); stopWatch.stop(); //计时结束(记录总共花了多少时间) if (this.logStartupInfo) { new StartupInfoLogger(this.mainApplicationClass) .logStarted(getApplicationLog(), stopWatch); } return context; } catch (Throwable ex) { handleRunFailure(context, listeners, ex); throw new IllegalStateException(ex); } }
private ConfigurableApplicationContext doRun(SpringApplicationRunListeners listeners, String... args) { ConfigurableApplicationContext context; // Create and configure the environment ConfigurableEnvironment environment = getOrCreateEnvironment(); //创建Environment configureEnvironment(environment, args); //配置Environment(包括配置要使用的PropertySource和Profile) listeners.environmentPrepared(environment); //事件发布器发布ApplicationEnvironmentPreparedEvent事件,所有监听了该事件的ApplicationListener执行相应逻辑 if (isWebEnvironment(environment) && !this.webEnvironment) { environment = convertToStandardEnvironment(environment); } if (this.bannerMode != Banner.Mode.OFF) { printBanner(environment); } // Create, load, refresh and run the ApplicationContext context = createApplicationContext(); //创建ApplicationContext容器 context.setEnvironment(environment); //设置Environment到容器 postProcessApplicationContext(context); applyInitializers(context); //执行所有的ApplicationContextInitializer的initial方法,对创建出来的ApplicationContext容器进行初始化 listeners.contextPrepared(context); if (this.logStartupInfo) { logStartupInfo(context.getParent() == null); logStartupProfileInfo(context); } // Add boot specific singleton beans ApplicationArguments applicationArguments = new DefaultApplicationArguments(args); context.getBeanFactory().registerSingleton("springApplicationArguments", applicationArguments); // Load the sources Set<Object> sources = getSources(); Assert.notEmpty(sources, "Sources must not be empty"); load(context, sources.toArray(new Object[sources.size()])); //将之前通过@EnableAutoConfiguration的所有配置以及其他形式的IOC容器加载到已经准备完毕的ApplicationContext listeners.contextLoaded(context); //事件发布器将所有的ApplicationListener注册给当前的ApplicationContext,之后发布ApplicationPreparedEvent事件 // Refresh the context refresh(context); //刷新ApplicationContext if (this.registerShutdownHook) { try { context.registerShutdownHook(); } catch (AccessControlException ex) { // Not allowed in some environments. } } afterRefresh(context, applicationArguments); listeners.finished(context, null); return context; }
步骤总结:
- 设置计时器,记录当前时间
- 该类是一个非线程的安全的,如果自己使用要考虑多线程的情况.
- 设置java.awt.headless为true或false
- java.awt.headless是J2SE的一种模式用于在缺少显示屏、键盘或者鼠标时的系统配置,很多监控工具如jconsole 需要将该值设置为true
- 获取事件发布器(用于控制所有事件的执行时机)
- 事件发布器发布ApplicationStartedEvent事件,所有监听了该事件的ApplicationListener实现类执行逻辑
- 创建并配置Environment(包括配置要使用的PropertySource和Profile)
- PropertySource主要是读取SpringApplication.setDefaultProperties指定的默认属性 + 命令行属性
- 通常,只有命令行属性,而且该属性会addFirst,说明优先级是最高的!!!
- Profile主要是读取application-{level}.properties中的内容
- 需要配置:"spring.active.profiles"
- 关于配置文件的一系列问题 见附 5 springboot之配置文件
- PropertySource主要是读取SpringApplication.setDefaultProperties指定的默认属性 + 命令行属性
- 事件发布器发布ApplicationEnvironmentPreparedEvent事件,所有监听了该事件的ApplicationListener执行相应逻辑
- 创建ApplicationContext容器
- 设置Environment到容器
- 执行所有的ApplicationContextInitializer的initial方法,对创建出来的ApplicationContext容器进行初始化
- 将之前通过@EnableAutoConfiguration的所有配置以及其他形式的IOC容器加载到已经准备完毕的ApplicationContext
- 装载beanDefinition到ApplicationContext(之后在使用Bean的时候,直接由beanDefinition初始化为bean)
- 事件发布器将所有的ApplicationListener注册给当前的ApplicationContext,之后发布ApplicationPreparedEvent事件
- 刷新ApplicationContext
- 这里如果有ContextRefreshedEvent的监听器,那么此时就会触发其onApplication方法
- 结束计时,记录整个启动时间
以上红色部分就是核心步骤!
参考:
http://www.jianshu.com/p/692b10aef052
http://zhaox.github.io/java/2016/03/22/spring-boot-start-flow
《springboot揭秘-快速构建微服务体系》