2. Spring Cloud Context:Application Context Services

Spring Boot 对于如何使用 Spring 构建 application 有一个自以为是的观点。例如,它具有 common configuration files 的常规位置,并具有_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)以高优先级添加,因此它们不能被本地 configuration 覆盖。

bootstrap context 使用不同的约定来查找外部 configuration 而不是 main application context。您可以使用bootstrap.yml而不是application.yml(或.properties),保持 bootstrap 和 main context 的外部 configuration 很好地分开。以下清单显示了一个 example:

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。

您可以通过设置spring.cloud.bootstrap.enabled=false(对于 example,在系统 properties 中)完全禁用 bootstrap process。

2.2 Application Context 层次结构

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

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

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

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

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

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

2.3 更改 Bootstrap Properties 的位置

可以通过设置spring.cloud.bootstrap.name(默认值:bootstrap)或spring.cloud.bootstrap.location(默认值:空)来指定bootstrap.yml(或.properties)位置 - 对于 example,在 System properties 中。这些 properties 的行为类似于具有相同 name 的spring.config.*变体。实际上,它们用于通过在Environment中设置 properties 来设置引导程序ApplicationContext。如果有一个 active profile(来自spring.profiles.active或通过 context 中的Environment API,你是 building),那个 profile 中的 properties 也会被加载,与常规 Spring Boot 应用程序中的 properties 相同 - 对于 example,从bootstrap-development.properties对于development profile 。

2.4 覆盖 Remote Properties 的值

由 bootstrap context 添加到 application 的 property 源通常是“remote”(来自 example,来自 Spring Cloud Config Server)。默认情况下,它们无法在本地重写。如果要让 applications 使用自己的 System properties 或 config files 覆盖 remote properties,则 remote property 源必须通过设置spring.cloud.config.allowOverride=true来授予它权限(它不能在本地设置它)。设置 flag 后,两个 finer-grained 设置控制 remote properties 相对于 system properties 和 application 的本地 configuration 的位置:

  • spring.cloud.config.overrideNone=true:从任何本地 property 源覆盖。

  • spring.cloud.config.overrideSystemProperties=false:只有系统 properties,命令 line arguments 和环境变量(但不是本地 config files)才应覆盖 remote 设置。

2.5 自定义 Bootstrap Configuration

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

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

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

2.6 自定义 Bootstrap Property Sources

bootstrap process 添加的外部 configuration 的默认 property 源是 Spring Cloud 配置服务器,但您可以通过将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是即将创建的ApplicationContext的一个 - 换句话说,我们为其提供其他 property 源的那个。它已经有了正常的 Spring Boot-provided property 源,因此您可以使用它们来查找特定于此Environment的 property 源(对于 example,通过在spring.application.name上键入它,就像在默认的 Spring Cloud Config Server property 源定位器中所做的那样)。

如果你在其中创建一个包含此 class 的 jar,然后添加包含以下内容的META-INF/spring.factories,那么customProperty PropertySource将出现在 class 路径中包含该 jar 的任何 application 中:

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

2.7 Logging Configuration

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

要使 Spring Cloud 正确初始化 logging configuration,您不能使用自定义前缀。例如,在初始化 logging 系统时,Spring Cloud 将无法识别使用custom.loggin.logpath

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播放到所有实例,而不是让它们轮询更改(对于 example,使用Spring Cloud Bus)。

EnvironmentChangeEvent涵盖了一大类 class 的刷新用例,为 long,因为您实际上可以对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会得到特殊处理。这个 feature 解决了有状态 beans 的问题,只有在初始化时才会注入 configuration。例如,如果DataSource在通过Environment更改数据库 URL 时具有打开的连接,那么您可能希望这些连接的持有者能够完成他们正在做的事情。然后,下一个 time 从池中借用一个连接,它得到一个新的 URL。

有时,甚至可能必须在一些只能初始化一次的 beans 上应用@RefreshScope annotation。如果 bean 是“不可变的”,则必须使用@RefreshScope注释 bean 或在 property key spring.cloud.refresh.extra-refreshable下指定类名。

如果您自己创建DataSource bean 并且 implementation 是HikariDataSource,则 return 返回最具体的类型,在本例中为HikariDataSource。否则,您需要设置spring.cloud.refresh.extra-refreshable=javax.sql.DataSource

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

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

要公开/refresh端点,您需要在 application 中添加以下 configuration:

management:
  endpoints:
    web:
      exposure:
        include: refresh

@RefreshScope(在技术上)在@Configuration class 上工作,但它可能会导致令人惊讶的行为。例如,它并不意味着该 class 中定义的所有@Beans本身都在@RefreshScope中。具体来说,任何依赖于那些 beans 的东西都不能依赖于它们在启动刷新时被更新,除非它本身在@RefreshScope中。在这种情况下,它在刷新时重建,其依赖项为 re-injected。那时,他们是 re-initialized 从刷新的@Configuration)。

2.10 加密和解密

Spring Cloud 有一个Environment pre-processor 用于在本地解密 property 值。它遵循与 Config Server 相同的规则,并通过encrypt.*具有相同的外部配置。因此,您可以使用{cipher}*形式的加密值,并且如果有一个有效的 key,则在主 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 文件夹中,以便使用 JRE/JDK x64/x86 的 version。

2.11 Endpoints

对于 Spring Boot Actuator application,可以使用一些额外的 management endpoints。您可以使用:

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

  • /actuator/refresh到 re-load boot strap context 并刷新@RefreshScope beans。

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

  • /actuator/pause/actuator/resume用于调用Lifecycle方法(ApplicationContext上的stop()start())。

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