zoukankan      html  css  js  c++  java
  • springboot启动过程(2)-run方法

    1 springApplication的run
      run方法主要是用于创造spring容器ConfigurableApplicationContext对象。

    public ConfigurableApplicationContext run(String... args) {
      StopWatch stopWatch = new StopWatch(); // 构造一个任务执行观察器
      stopWatch.start(); // 开始执行,记录开始时间
      ConfigurableApplicationContext context = null;
      configureHeadlessProperty();
      // 获取SpringApplicationRunListeners,内部只有一个EventPublishingRunListener
      SpringApplicationRunListeners listeners = getRunListeners(args);
      // 会封装成SpringApplicationEvent事件然后广播出去给SpringApplication中的listeners所监听
      // 这里接受ApplicationStartedEvent事件的listener会执行相应的操作
      listeners.started();
      try {
      // 构造一个应用程序参数持有类
      ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);

      //创建并配置环境

      ConfigurableEnvironment environment = prepareEnvironment(listeners,applicationArguments);
      //输出banner

          Banner printedBanner = printBanner(environment);
      context = createApplicationContext();
      analyzers = new FailureAnalyzers(context);
      prepareContext(context, environment, listeners, applicationArguments,printedBanner);
      refreshContext(context);
      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, ex); // 这个过程报错的话会执行一些异常操作、然后广播出ApplicationFailedEvent事件给相应的监听器执行
      throw new IllegalStateException(ex);
      }
    }

    2 run的过程 

      按顺序看run,发现执行了下面这些过程。

         (1 )stopWatch 记录开始结束时间,configureHeadlessProperty 设置headless模式,awt的headless,一般运行在服务器端,在没有显示器和鼠标键盘的模式下工作,模拟输入输出设备功能。

        (2)springApplicationListeners: 这个类包含了SpringApplicationRunlistener的集合和一个日志类。SpringApplicationRunlistener也是通过spring.factories加载,如下可以看到,就包含一种EventPublishingRunListener。
      org.springframework.boot.SpringApplicationRunListener=
      org.springframework.boot.context.event.EventPublishingRunListener
      EventPublishingRunListener通过看源码,发现包含了started environmentPrepared contextPrepared contextLoaded等方法,基本都是包装特定event并发event。配合run函数的代码如下,可以得知,springApplicationListeners主要负责在run函数的各个阶段,发起事件。比如在创建spring容器的前后调用了start和finish方法,在创建容器时,把listener当参数传入便于在各个时间发起事件。

       (3)prepareEnvironment  创建并设置环境 

      private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners,ApplicationArguments applicationArguments) {
      // Create and configure the environment
        ConfigurableEnvironment environment = getOrCreateEnvironment();
        configureEnvironment(environment, applicationArguments.getSourceArgs());
        listeners.environmentPrepared(environment);
        if (isWebEnvironment(environment) && !this.webEnvironment) {
          environment = convertToStandardEnvironment(environment);
        }
        return environment;
      }

         如上,设置环境分几个步骤,getOrderCreateEnvironment获得一个标准环境对象StandardEnvironment,然后configureEnvironment进行配置。其中configureEnvironment 包含两个配置,configurePropertySources和configureProfiles两个方法。Environment代表程序运行环境,包含两种信息,一个是profiles,描述各种bean defination,另一种是properties描述系统配置,包括配置文件 jvm属性文件 环境变量等。configureEnvironment方法先是调用configurePropertySources来配置properties,然后调用configureProfiles来配置profiles。然后listener发出事件。

        (4)pringBnner 打印banner,打印banner信息,即启动时出现的logo信息。

        (5)createApplicationContext  创建spring容器。如果是web程序,那么构造org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext容器,否则构造org.springframework.context.annotation.AnnotationConfigApplicationContext容器

        (6)prepareContext    首先调用了postProcessApplicationContext(context),如果是web程序并且是spring web容器,那么设置实例命名生成器并注册,同时注册资源加载器并注册。然后调用applyInitializers(context),遍历每个初始化器,调用相应的innitialize方法让初始化器开始工作。

         (7)refreshContext(context) 刷新spring容器,内部做很多事情,包括springFactory设置,BeanFactoryPostProcessor接口执行,BeanPostProcessor接口执行,自动化配置类解析,条件注解解析,国际化的初始化等。

       (8)afterRefresh  调用了 callRunners,主要是得到所有的CommonandLineRunner和ApplicationRunner, 使用 @Order(value=x)设置排序值,可以支持自定义runner完成自己需求。

    private void callRunners(ApplicationContext context, ApplicationArguments args) {
      List<Object> runners = new ArrayList<Object>();
      // 找出Spring容器中ApplicationRunner接口的实现类
      runners.addAll(context.getBeansOfType(ApplicationRunner.class).values());
      // 找出Spring容器中CommandLineRunner接口的实现类
      runners.addAll(context.getBeansOfType(CommandLineRunner.class).values());
      // 对runners进行排序
      AnnotationAwareOrderComparator.sort(runners);
      // 遍历runners依次执行
          for (Object runner : new LinkedHashSet<Object>(runners)) {
        if (runner instanceof ApplicationRunner) { // 如果是ApplicationRunner,进行ApplicationRunner的run方法调用
          callRunner((ApplicationRunner) runner, args);
        }
      if (runner instanceof CommandLineRunner) { // 如果是CommandLineRunner,进行CommandLineRunner的run方法调用
          callRunner((CommandLineRunner) runner, args);
        }
      }
    }

  • 相关阅读:
    WORD窗体保护密码清除
    在Fedora 23 Server和Workstation上安装LAMP(Linux, Apache, MariaDB和PHP)
    firefox 提示 ssl_error_unsupported_version 的解决方法
    算法题:求一个序列S中所有包含T的子序列(distinct sub sequence)
    Django模板输出Dict所有Value的效率问题
    笔记:LNK2001不代表链接器真的需要链接相关符号
    Windows Restart Manager 重启管理器
    advapi32.dll kernel32.dll 中的两套注册表API
    使用GDI+保存带Alpha通道的图像(续)
    使用GDI+保存带Alpha通道的图像
  • 原文地址:https://www.cnblogs.com/lkdirk/p/7127795.html
Copyright © 2011-2022 走看看