zoukankan      html  css  js  c++  java
  • Springcloud 引导上下文

          SpringCloud为我们提供了bootstrap.properties的属性文件,我们可以在该属性文件里做我们的服务配置。可是,我们知道SpringBoot已经为我们提供了做服务配置的属性文件application.properties,那么这两个配置文件有什么区别呢?在SpringCloud里是否能用bootstrap代替application做服务的配置?要解决这个问题,我们必须先讨论一下SpringCloud的引导。

     一、  官方文档描述

    引导应用程序上下文

      一个Spring Cloud应用程序通过创建一个“引导”上下文来进行操作,这个上下文是主应用程序的父上下文。开箱即用,负责从外部源加载配置属性,还解密本地外部配置文件中的属性。这两个上下文共享一个Environment,这是任何Spring应用程序的外部属性的来源。Bootstrap属性的优先级高,因此默认情况下不能被本地配置覆盖。

    引导上下文使用与主应用程序上下文不同的外部配置约定,因此使用bootstrap.yml application.yml(或.properties)代替引导和主上下文的外部配置。例:bootstrap.yml

    spring:
      application:
        name: foo
      cloud:
        config:
          uri: ${SPRING_CONFIG_URI:http://localhost:8888}

    如果您的应用程序需要服务器上的特定于应用程序的配置,那么设置spring.application.name(在bootstrap.ymlapplication.yml)中是个好主意。

    您可以通过设置spring.cloud.bootstrap.enabled=false(例如在系统属性中)来完全禁用引导过程。

    二、引导上下文

     1. 关于引导上下文位置

      

          这里我们可以发现几个关键的类,其中BootstrapApplicationListener是核心中的核心,可自行查看源码

         这个类是一个监听器,它用于监听ApplicationEnvironmentPreparedEvent事件,而EventPublishingRunListener在SpringBoot启动时会触发该事件。如果不理解的这个类的朋友请务必先了解SpringBoot启动过程

        2.这个上下文是主应用程序的父上下文

          这个工作主要分为两个层面:1.创建上下文引导 2.设置为其为当前程序的父级上下文

         

       1) 我们先看看onApplicationEvent方法,该方法首先读取spring.cloud.bootstrap.enabled的属性值如果为false,那么就直接return。这也就是官方文档里的说明可以用此属性禁用引导的理由。

       2)紧接着它会从当前应用程序SpringApplication试着在所有的ApplicationInitializer中获取ParentContextApplicationContextInitializer,如果找到的话就把该类下的parent做为引导上下文。

       3)如果没有找到ParentContextApplicationContextInitializer,则通过 bootstrapServiceContext方法来创建引导上下文,其中如下代码请大家留意下:

        List<String> names = SpringFactoriesLoader
                    .loadFactoryNames(BootstrapConfiguration.class, classLoader);

             看到SpringFactoriesLoader不用想一定会在META-INF/spring.factoies里找配置的BootstrapConfiguration的进行实例化

                 

     4)通过如下代码创建引导上下文对象:

    复制代码
    SpringApplicationBuilder builder = new SpringApplicationBuilder()
                    .profiles(environment.getActiveProfiles()).bannerMode(Mode.OFF)
                    .environment(bootstrapEnvironment)
                    .properties("spring.application.name:" + configName)
                    .registerShutdownHook(false).logStartupInfo(false).web(false);
            if (environment.getPropertySources().contains("refreshArgs")) {
                // If we are doing a context refresh, really we only want to refresh the
                // Environment, and there are some toxic listeners (like the
                // LoggingApplicationListener) that affect global static state, so we need a
                // way to switch those off.
                builder.application()
                        .setListeners(filterListeners(builder.application().getListeners()));
            }
            List<Class<?>> sources = new ArrayList<>();
            for (String name : names) {
                Class<?> cls = ClassUtils.resolveClassName(name, null);
                try {
                    cls.getDeclaredAnnotations();
                }
                catch (Exception e) {
                    continue;
                }
                sources.add(cls);
            }
            AnnotationAwareOrderComparator.sort(sources);
            builder.sources(sources.toArray(new Class[sources.size()]));
            final ConfigurableApplicationContext context = builder.run();
    复制代码

      

    5)最后通过如下方法设置引导上下文为当前应用程序的上下文:

    // Make the bootstrap context a parent of the app context
            addAncestorInitializer(application, context);

       3. 负责从外部源加载配置属性,还解密本地外部配置文件中的属性

      

        开箱即用,理解起来很简单。通过2.2分析,引导程序在SpringBoot的启动前就帮我们创建好了,当然也就开箱即用了。

     下面我们看一下spring-cloud-context.jar下的META-INF/spring.factoies文件:

        

    # AutoConfiguration
    org.springframework.boot.autoconfigure.EnableAutoConfiguration=
    org.springframework.cloud.autoconfigure.ConfigurationPropertiesRebinderAutoConfiguration,
    org.springframework.cloud.autoconfigure.RefreshAutoConfiguration,
    org.springframework.cloud.autoconfigure.RefreshEndpointAutoConfiguration,
    org.springframework.cloud.autoconfigure.LifecycleMvcEndpointAutoConfiguration
    
    # Application Listeners
    org.springframework.context.ApplicationListener=
    org.springframework.cloud.bootstrap.BootstrapApplicationListener,
    org.springframework.cloud.bootstrap.LoggingSystemShutdownListener,
    org.springframework.cloud.context.restart.RestartListener
    
    # Bootstrap components
    org.springframework.cloud.bootstrap.BootstrapConfiguration=
    org.springframework.cloud.bootstrap.config.PropertySourceBootstrapConfiguration,
    org.springframework.cloud.bootstrap.encrypt.EncryptionBootstrapConfiguration,
    org.springframework.cloud.autoconfigure.ConfigurationPropertiesRebinderAutoConfiguration,
    org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration
    View Code

     我们来看一下  BootstrapConfiguration下面配置的引导程序类:

        org.springframework.cloud.bootstrap.config.PropertySourceBootstrapConfiguration:这个类主要解析加载外部化配置属性

        org.springframework.cloud.bootstrap.encrypt.EncryptionBootstrapConfiguration:主要配置文件中前缀为{cipher}的相关解密,熟悉spring-boot-starter-security在springcloud应用的朋友一定不陌生

        org.springframework.cloud.autoconfigure.ConfigurationPropertiesRebinderAutoConfiguration:主要是监听EnvironmentChangeEvent事件用于刷新@ConfigurationProperties标记的配置

        org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration:主要解析配置文件中的${}占位符

     4. 这两个上下文共享一个Environment

           既然引导上下文为当前主程序的父级上下文,那么就可以确定他们共享Environment,至于为什么请阅读文章第一部分

     5. BootStrap属性的优先级高,因此默认情况下不能被本地配置覆盖

          对于引导程序bootstrap.yml比application.yml优先级更高,更不可能被application.yml文件里的所覆盖

     三、总结

      1)引导程序上下文在prepareEnvironment的阶段就会被创建,创建时会读取bootstrap.properties|yml 在内容作为引导配置, 因此bootstrap优先于application加载。引导程序非常类似于bios,而bootstrap.application就相当于设置bios的相关参数

      2)boostrap的属性文件在以下情景下会使用:

        配置中心:config-server里请用bootstrap属性文件

          解密属性文件时,最好使用bootstrap属性文件

        需要自定义引导程序时使用bootstrap属性文件,主要一定不要被我们主程序扫描到

      3)application会覆盖bootstrap中的非引导配置,因此不建议两种类型配置文件同时存在。简单粗暴的做法是在springcloud应用中用bootstrap属性文件代替application一统江湖嘛,毕竟Envrionment是共享的。

      4)  在阅读官方文档时,一定要结合源代码深入分析,才能更好的理解其用意

  • 相关阅读:
    SA练习题总结-篇一
    树上距离(树形DP)
    Codeforces Round #633(Div.2) E. Perfect Triples
    Codeforces Round #633 (Div. 2) D.Edge Weight Assignment
    问题 B: FZB(树形DP+边记忆化)
    【Matlab】自学笔记——基础知识篇
    【Python科学计算】Numpy——ndarry
    退役总结
    [树的遍历]树的遍历(PTA)
    [stl]集合相似度(PTA)
  • 原文地址:https://www.cnblogs.com/whx7762/p/11232019.html
Copyright © 2011-2022 走看看