1 public ConfigurableApplicationContext run(String... args) {
2 StopWatch stopWatch = new StopWatch(); //设置计时器
3 stopWatch.start(); //记录当前时间
4 ConfigurableApplicationContext context = null;
5 configureHeadlessProperty(); //设置java.awt.headless为true或false
6 SpringApplicationRunListeners listeners = getRunListeners(args);//获取事件发布器(控制所有事件的执行时机)
7 listeners.started(); //事件发布器发布ApplicationStartedEvent事件,所有监听了该事件的ApplicationListener实现类执行逻辑
8 try {
9 context = doRun(listeners, args);
10 stopWatch.stop(); //计时结束(记录总共花了多少时间)
11 if (this.logStartupInfo) {
12 new StartupInfoLogger(this.mainApplicationClass)
13 .logStarted(getApplicationLog(), stopWatch);
14 }
15 return context;
16 }
17 catch (Throwable ex) {
18 handleRunFailure(context, listeners, ex);
19 throw new IllegalStateException(ex);
20 }
21 }
1 private ConfigurableApplicationContext doRun(SpringApplicationRunListeners listeners,
2 String... args) {
3 ConfigurableApplicationContext context;
4 // Create and configure the environment
5 ConfigurableEnvironment environment = getOrCreateEnvironment(); //创建Environment
6 configureEnvironment(environment, args); //配置Environment(包括配置要使用的PropertySource和Profile)
7 listeners.environmentPrepared(environment); //事件发布器发布ApplicationEnvironmentPreparedEvent事件,所有监听了该事件的ApplicationListener执行相应逻辑
8 if (isWebEnvironment(environment) && !this.webEnvironment) {
9 environment = convertToStandardEnvironment(environment);
10 }
11
12 if (this.bannerMode != Banner.Mode.OFF) {
13 printBanner(environment);
14 }
15
16 // Create, load, refresh and run the ApplicationContext
17 context = createApplicationContext(); //创建ApplicationContext容器
18 context.setEnvironment(environment); //设置Environment到容器
19 postProcessApplicationContext(context);
20 applyInitializers(context); //执行所有的ApplicationContextInitializer的initial方法,对创建出来的ApplicationContext容器进行初始化
21 listeners.contextPrepared(context);
22 if (this.logStartupInfo) {
23 logStartupInfo(context.getParent() == null);
24 logStartupProfileInfo(context);
25 }
26
27 // Add boot specific singleton beans
28 ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
29 context.getBeanFactory().registerSingleton("springApplicationArguments",
30 applicationArguments);
31
32 // Load the sources
33 Set<Object> sources = getSources();
34 Assert.notEmpty(sources, "Sources must not be empty");
35 load(context, sources.toArray(new Object[sources.size()])); //将之前通过@EnableAutoConfiguration的所有配置以及其他形式的IOC容器加载到已经准备完毕的ApplicationContext
36 listeners.contextLoaded(context); //事件发布器将所有的ApplicationListener注册给当前的ApplicationContext,之后发布ApplicationPreparedEvent事件
37
38 // Refresh the context
39 refresh(context); //刷新ApplicationContext
40 if (this.registerShutdownHook) {
41 try {
42 context.registerShutdownHook();
43 }
44 catch (AccessControlException ex) {
45 // Not allowed in some environments.
46 }
47 }
48 afterRefresh(context, applicationArguments);
49 listeners.finished(context, null);
50 return context;
51 }
步骤总结:
- 设置计时器,记录当前时间
- 该类是一个非线程的安全的,如果自己使用要考虑多线程的情况.
- 设置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揭秘-快速构建微服务体系》