2. Spring Cloud Context:Application Context Services

Spring Boot 对于如何使用 Spring 构建 application 有一个自以为是的观点:例如,它具有 common configuration 文件的常规位置,_comnd management 和监视任务的 endpoints。 Spring Cloud 构建于此之上,并添加了一些 features,可能系统中的所有组件都会使用或偶尔需要。

2.1 Bootstrap Application Context

Spring Cloud application 通过 creating“bootstrap”context 来操作,它是主 application 的 parent context。它开箱即用,它负责从外部源加载 configuration properties,并解密本地外部 configuration files 中的 properties。这两个上下文共享一个Environment,它是任何 Spring application 的外部 properties 的源。 Bootstrap properties(不是bootstrap.properties,但是在引导阶段加载的 properties)以高优先级添加,因此默认情况下它们不能被 local configuration 覆盖。

bootstrap context 使用不同的约定来查找外部 configuration 而不是主 application context,因此使用bootstrap.yml而不是application.yml(或.properties),保持 bootstrap 和 main context 的外部 configuration 很好地分开。 例:

bootstrap.yml.

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

如果您的 application 需要来自服务器的任何 application-specific configuration,那么设置spring.application.name(在bootstrap.ymlapplication.yml中)是一个很好的 idea。

您可以通过在 System properties 中设置spring.cloud.bootstrap.enabled=false(e.g. )来完全禁用 bootstrap process。

2.2 Application Context 层次结构

如果从SpringApplicationSpringApplicationBuilder build application context,则将 Bootstrap context 作为 parent 添加到该 context。它是 Spring 的一个 feature,child 上下文从它们的 parent 继承 property 源和 profiles,所以“main”application context 将包含额外的 property 源,相比之下 building 相同的 context 没有 Spring Cloud Config。额外的 property 来源是:

  • “bootstrap”:如果在 Bootstrap context 中找到任何PropertySourceLocators,则可选CompositePropertySource具有高优先级,并且它们具有 non-empty properties。 example 将是 Spring Cloud Config Server 的 properties。有关如何自定义此 property 源的内容的说明,请参阅下面

  • “applicationConfig:[18]”(和朋友,如果 Spring profiles 是 active)。如果你有一个bootstrap.yml(或 properties),那么这些 properties 用于配置 Bootstrap context,然后在设置 parent 时将它们添加到 child context。它们的优先级低于application.yml(或 properties)以及添加到 child 的任何其他 property 源,作为 creating Spring Boot application 的 process 的正常部分。有关如何自定义这些 property 源的内容的说明,请参阅下面

由于 property 源的_ororder 规则,“bootstrap”条目优先,但请注意,这些条目不包含来自bootstrap.yml的任何数据,它具有非常低的优先级,但可用于设置默认值。

您可以通过简单地设置您创建的任何ApplicationContext的 parent context 来扩展 context 层次结构 e.g. 使用自己的接口,或使用SpringApplicationBuilder方便方法(parent()child()sibling())。 bootstrap context 将是您自己创建的最高级祖先的 parent。层次结构中的每个 context 都有自己的“bootstrap”property 源(可能为空),以避免无意中将值从 parents 降级到它们的后代。如果存在 Config Server,层次结构中的每个 context(原则上)也可以具有不同的spring.application.name,因此具有不同的 remote property 源。正常的 Spring application context 行为规则适用于 property 解决方案:来自 child context 的 properties 覆盖 parent,name 和 property source name 中的 properties(如果 child 有一个 property 源与 parent 具有相同的 name,来自 parent 不包含在 child 中。

请注意,SpringApplicationBuilder允许您在整个层次结构中共享Environment,但这不是默认值。因此,特别是兄弟情境不需要具有相同的 profiles 或 property 源,即使它们将与 parent 共享 common 事物。

2.3 更改 Bootstrap Properties 的位置

bootstrap.yml(或.properties)位置可以使用spring.cloud.bootstrap.name(默认“bootstrap”)或spring.cloud.bootstrap.location(默认为空)e.g 指定。在 System properties 中。那些 properties 的行为类似于具有相同 name 的spring.config.*变体,实际上它们用于通过在Environment中设置 properties 来设置 bootstrap ApplicationContext。如果有 active profile(来自spring.profiles.active或通过 context 中的Environment API,你是 building),那么 profile 中的 properties 也将被加载,就像在常规的 Spring Boot 应用程序中一样,e.g. 来自bootstrap-development.properties的“发展”profile。

2.4 覆盖 Remote Properties 的值

由 bootstrap context 添加到 application 的 property 源通常是“remote”(来自 Config Server 的 e.g. ),默认情况下,除了命令 line 之外,它们不能在本地重写。如果要允许 applications 使用自己的 System properties 或 config files 覆盖 remote properties,则 remote property 源必须通过设置spring.cloud.config.allowOverride=true来授予它权限(它不能在本地设置它)。一旦设置了 flag,就会有一些更细粒度的设置来控制 remote properties 相对于 System properties 的位置和 application 的本地 configuration:spring.cloud.config.overrideNone=true以覆盖任何本地 property 源,如果只有 System properties 和 env vars 应该覆盖spring.cloud.config.overrideSystemProperties=false remote 设置,但不是本地配置 files。

2.5 自定义 Bootstrap Configuration

可以通过在 key org.springframework.cloud.bootstrap.BootstrapConfiguration下向/META-INF/spring.factories添加条目来训练 bootstrap context 以执行任何操作。这是 Spring @Configuration classes 的 comma-separated 列表,它将用于创建 context。您可以在此处创建任何希望可用于主 application context 以进行自动装配的 beans,并且@Beans类型的@Beans还有一个特殊的 contract。如果要控制启动顺序(默认 order 是“last”),Class 可以用@Order标记。

添加自定义BootstrapConfiguration时要小心,你添加的 classes 错误地不是@ComponentScanned到你的“main”application context 中,可能不需要它们。对或@SpringBootApplication带注释的 configuration classes 尚未涵盖的 boot configuration classes 使用单独的包 name。

引导程序 process _end 通过将初始化程序注入主SpringApplication实例(i.e.正常 Spring Boot 启动顺序,无论它是作为独立应用程序运行还是部署在 application 服务器中)。首先从spring.factories中找到的 classes 创建 bootstrap context,然后在启动之前将类型@Beans添加到主SpringApplication

2.6 自定义 Bootstrap Property Sources

bootstrap process 添加的外部 configuration 的默认 property 源是 Config Server,但您可以通过将PropertySourceLocator类型的 beans 添加到 bootstrap context(通过spring.factories)来添加其他源。例如,您可以使用它来插入来自不同服务器或数据库的其他 properties。

作为示例,请考虑以下简单的自定义定位器:

@Configuration
public class CustomPropertySourceLocator implements PropertySourceLocator {

    @Override
    public PropertySource<?> locate(Environment environment) {
        return new MapPropertySource("customProperty",
                Collections.<String, Object>singletonMap("property.from.sample.custom.source", "worked as intended"));
    }

}

传入的Environment是要创建的ApplicationContextEnvironment,i.e。我们正在提供额外的 property 来源的那个。它已经有了正常的 Spring Boot-provided property 源,因此您可以使用它们来查找特定于此Environment的 property 源(e.g. 通过在spring.application.name上键入它,就像在默认的 Config Server property 源定位器中所做的那样)。

如果在其中创建带有此 class 的 jar,然后添加包含以下内容的META-INF/spring.factories

org.springframework.cloud.bootstrap.BootstrapConfiguration=sample.custom.CustomPropertySourceLocator

然后“customProperty”PropertySource将显示在任何 application 中,其 class 路径上包含 jar。

2.7 Logging Configuration

如果你打算使用 Spring Boot 来配置 log 设置,你应该将这个 configuration 放在`bootstrap。[72]中,如果你希望它适用于所有的 events。

2.8 环境变化

application 将侦听EnvironmentChangeEvent并以几种标准方式对更改作出反应(用户可以正常方式将ApplicationListeners添加为@Beans)。当观察到EnvironmentChangeEvent时,它将有一个已更改的 key 值列表,application 将使用这些值:

  • Re-bind context 中的任何@ConfigurationProperties beans

  • logging.level.*中的任何 properties 设置 logger 级别

请注意,Config Client 默认情况下不会轮询Environment中的更改,通常我们不建议使用这种方法来检测更改(尽管您可以使用@Scheduled annotation 进行设置)。如果你有一个 scaled-out client application,那么最好将EnvironmentChangeEvent播放到所有实例,而不是让它们轮询更改(e.g. 使用Spring Cloud Bus)。

EnvironmentChangeEvent涵盖了大型的 class 刷新用例,因为你实际上可以对Environment进行更改并发布 event(这些 API 是公共的,部分是核心 Spring)。您可以通过访问/configprops端点(正常 Spring Boot Actuator feature)来验证更改是否绑定到@ConfigurationProperties beans。例如,DataSource可以在运行时更改maxPoolSize(Spring Boot 创建的默认DataSource@ConfigurationProperties bean)并动态增加容量。 Re-binding @ConfigurationProperties不包括另一个大的 class 用例,你需要更多控制刷新,以及你需要在整个ApplicationContext上进行原子更改。为了解决这些问题,我们有@RefreshScope

2.9 刷新范围

当 configuration 更改时,标记为@RefreshScope的 Spring @Bean将得到特殊处理。这解决了有状态 beans 的问题,它们只在初始化时才会注入 configuration。例如,如果DataSource在通过Environment更改数据库 URL 时具有打开的连接,我们可能希望这些连接的持有者能够完成他们正在做的事情。然后在下一个 time 有人借用池中的连接时,他会使用新 URL 获取一个连接。

刷新范围 beans 是在使用它们时初始化的惰性代理(i.e.当调用方法时),并且范围充当初始化值的缓存。要在下一个方法调用上强制 bean 到 re-initialize,您只需要使其缓存条目无效。

RefreshScope是 context 中的 bean,它有一个公共方法refreshAll(),通过清除目标缓存来刷新范围内的所有 beans。还有一个refresh(String)方法可以通过 name 刷新单个 bean。此功能在/refresh端点(通过 HTTP 或 JMX)中公开。

@RefreshScope(在技术上)在@Configuration class 上工作,但它可能会导致令人惊讶的行为:e.g. 它不**意味着该 class 中定义的所有@Beans本身都是@RefreshScope。具体来说,任何依赖于那些 beans 的东西都不能依赖它们在启动刷新时被更新,除非它本身在@RefreshScope(它将在刷新时重建它的依赖 re-injected,此时它们将是 re-initialized 来自刷新@Configuration)。

2.10 加密和解密

Spring Cloud 有一个Environment pre-processor 用于在本地解密 property 值。它遵循与 Config Server 相同的规则,并通过encrypt.*具有相同的外部 configuration。因此,您可以使用{cipher}*形式的加密值和 long 作为 long,因为它们将在主 application context 获得Environment之前被解密。要在 application 中使用加密 features,您需要在 classpath(Maven co-ordinates“org.springframework.security:spring-security-rsa”)中包含 Spring Security RSA,并且还需要 JVM 中的全强度 JCE extensions。

如果由于“非法 key 大小”而得到 exception 并且您使用的是 Sun 的 JDK,则需要安装 Java Cryptography Extension(JCE)Unlimited Strength Jurisdiction Policy Files。有关更多信息,请参阅以下链接:

将 files 提取到 JDK/jre/lib/security 文件夹中(无论你使用哪个 version JRE/JDK x64/x86)。

2.11 Endpoints

对于 Spring Boot Actuator application,还有一些额外的 management endpoints:

  • POST 到/env以更新Environment并重新绑定@ConfigurationProperties和 log 级别

  • /refresh为 re-loading boot strap context 并刷新@RefreshScope beans

  • /restart用于关闭ApplicationContext并重新启动它(默认情况下禁用)

  • /pause/resume用于调用Lifecycle方法(ApplicationContextstop()start())

如果禁用/restart端点,则/pause/resume endpoints 也将被禁用,因为它们只是/restart的一个特例。