springboot源码解析-run()

叁叁肆2018-12-02 13:56

此文已由作者赵计刚薪授权网易云社区发布。

欢迎访问网易云社区,了解更多网易技术产品运营经验。


 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之配置文件
  • 事件发布器发布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揭秘-快速构建微服务体系》


免费体验云安全(易盾)内容安全、验证码等服务

更多网易技术、产品、运营经验分享请点击