<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      Spring Cloud Context模塊

       SpringCloud這個框架本身是建立在SpringBoot基礎之上的,所以使用SpringCloud的方式與SpringBoot相仿。也是通過類似如下代碼進行啟動。

           SpringApplication.run(XxxApplication.class, args);

      其中 XxxApplication.class 類上也需要添加 @SpringBootApplication注解。

      要使用SpringCloud框架,在pom文件中要確保引入  spring-cloud-starter 依賴包, spring-cloud-starter 依賴如下的 jar :

      <dependencies>
              <dependency>
                  <groupId>org.springframework.boot</groupId>
                  <artifactId>spring-boot-starter</artifactId>
              </dependency>
              <dependency>
                  <groupId>org.springframework.cloud</groupId>
                  <artifactId>spring-cloud-context</artifactId>
              </dependency>
              <dependency>
                  <groupId>org.springframework.cloud</groupId>
                  <artifactId>spring-cloud-commons</artifactId>
              </dependency>
      </dependencies>
              

      其中  spring-cloud-context-x.y.z.RELEASE.jar 和 spring-cloud-commons-x.y.z.RELEASE.jar 下的 META-INF 目錄下都包含  spring.factories 文件,所以可以把這兩個jar看作是springCloud程序的入口。

      SpringCloud在構建上下文 (即ApplicationContext實例)時,采用了Spring父子容器的設計,會在 SpringBoot構建的容器(后面稱之為應用容器)之上創建一父容器 Bootstrap Application Context .

      那么SpringCloud設計出Bootstrap Application Context ,并把它作為 應用容器的父容器的目的是什么呢:

             因為SpringCloud 作為一個微服務框架,需要使用全局的配置中心,而配置中心的配置是可以提供給應用容器的,所以在應用容器初始化和實例化Bean之前需要先完成配置中心的實例化,這個任務就由Bootstrap Application Context 來完成,而配置中心的相關配置屬性就從bootstrap.properties或bootstrap.yml文件中讀取。

             但要注意的是,在Bootstrap Application Context 啟動工作完成之后,其從bootstrap.properties或bootstrap.yml文件中讀取的配置,是會被應用容器對應的application.properties或yml文件中的同名屬性覆蓋的。

       

      下面從源碼角度來分析上面的論述:

      1. 代碼運行時還是從SpringApplication實例的run方法開始 ,此處會觸發 BootstrapApplicationListener 類中的代碼 , Bootstrap Application Context 的創建就是通過這個監聽器觸發的

      public ConfigurableApplicationContext run(String... args) {
              StopWatch stopWatch = new StopWatch();
              stopWatch.start();
              ConfigurableApplicationContext context = null;
              Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
              configureHeadlessProperty();
      //此處會加載spring-cloud-context提供的監聽器org.springframework.cloud.bootstrap.BootstrapApplicationListener.class SpringApplicationRunListeners listeners
      = getRunListeners(args); listeners.starting(); try { ApplicationArguments applicationArguments = new DefaultApplicationArguments( args);
      //此處會發布ApplicationEnvironmentPreparedEvent事件,觸發BootstrapApplicationListener中的代碼 ConfigurableEnvironment environment
      = prepareEnvironment(listeners, applicationArguments); configureIgnoreBeanInfo(environment); Banner printedBanner = printBanner(environment); context = createApplicationContext(); exceptionReporters = getSpringFactoriesInstances( SpringBootExceptionReporter.class, new Class[] { ConfigurableApplicationContext.class }, context); prepareContext(context, environment, listeners, applicationArguments, printedBanner); refreshContext(context); afterRefresh(context, applicationArguments); stopWatch.stop(); if (this.logStartupInfo) { new StartupInfoLogger(this.mainApplicationClass) .logStarted(getApplicationLog(), stopWatch); } listeners.started(context); callRunners(context, applicationArguments); } catch (Throwable ex) { handleRunFailure(context, ex, exceptionReporters, listeners); throw new IllegalStateException(ex); } try { listeners.running(context); } catch (Throwable ex) { handleRunFailure(context, ex, exceptionReporters, null); throw new IllegalStateException(ex); } return context; }

       

      2. Bootstrap Application Context 的實例化 ,由BootstrapApplicationListener類的 onApplicationEvent方法觸發

      public void onApplicationEvent(ApplicationEnvironmentPreparedEvent event) {
              ConfigurableEnvironment environment = event.getEnvironment();
      //可以通過環境變量 spring.cloud.bootstrap.enabled來禁止使用Bootstrap容器
      if (!environment.getProperty("spring.cloud.bootstrap.enabled", Boolean.class, true)) { return; } // 由于Bootstrap容器在創建時還是會再次調用上面步驟1的代碼,還會再次觸發BootstrapApplicationListener類這個方法,所以此處作個判斷,
                如果當前是Bootstrap容器的處理,則直接返回
      if (environment.getPropertySources().contains(BOOTSTRAP_PROPERTY_SOURCE_NAME)) { return; } ConfigurableApplicationContext context = null;
      //獲取配置文件的名字,默認為bootstrap.properties或.yml ,并且這個名字可以通過 spring.cloud.bootstrap.name在環境中配置 String configName
      = environment .resolvePlaceholders("${spring.cloud.bootstrap.name:bootstrap}"); for (ApplicationContextInitializer<?> initializer : event.getSpringApplication() .getInitializers()) {
      //從相應jar中的spring.factories文件中讀取初始化器的配置類實例,如果這個實例類是ParentContextApplicationContextInitializer類型
      則直接從該類中獲取到父容器,默認情況下,沒有提供這樣的類,下面這段代碼會跳過
      if (initializer instanceof ParentContextApplicationContextInitializer) { context = findBootstrapContext( (ParentContextApplicationContextInitializer) initializer, configName); } } if (context == null) {
      //此處分析見步驟3 context
      = bootstrapServiceContext(environment, event.getSpringApplication(), configName); event.getSpringApplication().addListeners(new CloseContextOnFailureApplicationListener(context)); } apply(context, event.getSpringApplication(), environment); }

       

      3. bootstrap容器的創建

      private ConfigurableApplicationContext bootstrapServiceContext(
                  ConfigurableEnvironment environment, final SpringApplication application,
                  String configName) {
               /**
      此處代碼主要是從各處獲取屬性配置,此處忽略
      **/

      // TODO: is it possible or sensible to share a ResourceLoader? SpringApplicationBuilder builder = new SpringApplicationBuilder() .profiles(environment.getActiveProfiles()).bannerMode(Mode.OFF) .environment(bootstrapEnvironment) // Don't use the default properties in this builder .registerShutdownHook(false).logStartupInfo(false) .web(WebApplicationType.NONE);

      //SpringApplicationBuilder的作用:1.構建SpringApplication 2.構建ApplicationContext
      //這里需要思考一下,springboot在啟動時已經構建了一個SpringApplication實例,為何此處又構建了一個
      //這是因為這個SpringApplication實例的構建環境和SringBoot原生構建的那個不同,看一下上一行代碼就能明白
      final SpringApplication builderApplication = builder.application(); if(builderApplication.getMainApplicationClass() == null){ builder.main(application.getMainApplicationClass()); } if (environment.getPropertySources().contains("refreshArgs")) { builderApplication .setListeners(filterListeners(builderApplication.getListeners())); }
      //從springFactories文件中查找BootstrapConfiguration的配置類 builder.sources(BootstrapImportSelectorConfiguration.
      class);

      //構建出BootstrapContext
      final ConfigurableApplicationContext context = builder.run(); context.setId("bootstrap");
      // 設置BootstrapContext成為應用Context的父容器,此處分析見步驟4 addAncestorInitializer(application, context); // It only has properties in it now that we don't want in the parent so remove // it (and it will be added back later) bootstrapProperties.remove(BOOTSTRAP_PROPERTY_SOURCE_NAME); mergeDefaultProperties(environment.getPropertySources(), bootstrapProperties); return context; }

       

       4. 設置BootstrapContext成為應用Context的父容器 (在SpringApplication實例中動態添加了一個初始化器,相當于給應用Context埋了個雷)

      private void addAncestorInitializer(SpringApplication application,
                  ConfigurableApplicationContext context) {
              boolean installed = false;
      //從spring.factories文件中獲取初始化器的配置類且類型為AncestorInitializer
      for (ApplicationContextInitializer<?> initializer : application .getInitializers()) { if (initializer instanceof AncestorInitializer) { installed = true; // New parent ((AncestorInitializer) initializer).setParent(context); } }
      //默認情況下是沒有配圍置AncestorInitializer這樣的類,此處是則執行由BootstrapListener提供的內部類
      if (!installed) {
      //將BootstrapContext作為父容器傳到AncestorInitializer實例中,并將其放入SpringApplication實例的初始器列表中 application.addInitializers(
      new AncestorInitializer(context)); } }

       

      5. 初始化器AncestorInitializer被觸發,是由應用Context的處理觸發的

      public void initialize(ConfigurableApplicationContext context) {  //這個context是應用Context
                  while (context.getParent() != null && context.getParent() != context) {
                      context = (ConfigurableApplicationContext) context.getParent();
                  }
                  reorderSources(context.getEnvironment());
      //完成應用容器的父容器的設置
      new ParentContextApplicationContextInitializer(this.parent) .initialize(context); }

       

      6. ParentContextApplicationContextInitializer代碼

      private static class ParentContextApplicationContextInitializer
                  implements ApplicationContextInitializer<ConfigurableApplicationContext> {
      
              private final ApplicationContext parent;
      
              ParentContextApplicationContextInitializer(ApplicationContext parent) {
                  this.parent = parent;
              }
      
              @Override
              public void initialize(ConfigurableApplicationContext applicationContext) {
                  applicationContext.setParent(this.parent);  //設置應用Context的父容器
              }
      
          }

       

      總結:

        1. SpringCloud Context模塊的功能  :主要是構建了一個Bootstrap容器,并讓其成為原有的springboot程序構建的容器的父容器。

        2. Bootstrap容器的作用:是為了預先完成一些bean的實例化工作,可以把Bootstrap容器看作是先頭部隊。

        3. Bootstrap容器的構建:是利用了Springboot的事件機制,當 springboot 的初始化 Environment  準備好之后會發布一個事件,這個事件的監聽器將負責完成Bootstrap容器的創建。構建時是使用 SpringApplicationBuilder 類來完成的。

             4. 如何讓Bootstrap容器與應用Context 建立父子關系 :由于Bootstrap容器與應用Context都是關聯著同一個SpringApplication實例,Bootstrap容器自己完成初始化器的調用之后,會動態添加了一個初始化器 AncestorInitializer,相當于給應用Context 埋了個雷 ,這個初始化器在應用容器進行初始化器調用執行時,完成父子關系的設置。

         

          

      posted @ 2019-03-08 16:44  杭州胡欣  閱讀(10020)  評論(2)    收藏  舉報
      主站蜘蛛池模板: 爱色精品视频一区二区| 又大又紧又粉嫩18p少妇| 99久久无码一区人妻a黑| 人人妻人人玩人人澡人人爽| 欧美丰满熟妇hdxx| 国产欧美一区二区精品性色| 中文有码字幕日本第一页| 亚洲中文字幕无码一区日日添| 色一情一乱一伦麻豆| 一本无码在线观看| 人妻综合专区第一页| 久久久av波多野一区二区| 亚洲婷婷综合色香五月| 亚洲午夜爱爱香蕉片| 国内精品久久人妻互换| 高级艳妇交换俱乐部小说| 成人亚洲国产精品一区不卡| 欧美亚洲综合成人a∨在线| 亚洲色一色噜一噜噜噜| 亚洲性日韩精品一区二区三区| 久久SE精品一区精品二区| 巴林左旗| 黑人异族巨大巨大巨粗| 天堂V亚洲国产V第一次| 亚洲中文字幕aⅴ天堂| 亚洲天堂成人一区二区三区| 激情综合色综合啪啪开心| 欧美日韩不卡视频合集| 极品少妇无套内射视频| 偷拍精品一区二区三区| 香蕉久久精品日日躁夜夜躁夏 | 日本少妇xxx做受| 日本一区二区a√成人片| 高清中文字幕国产精品| 欧美黑人又粗又大又爽免费| 国产一区二区三区精美视频 | 一区二区三区国产亚洲网站| 日韩精品一区二区三区激情视频| 国产成人精品久久性色av| 国产精品久久久久aaaa| 丁香花成人电影|