云原生是一种应用开发风格,鼓励在持续交付和价值驱动开发领域轻松采用最佳实践。相关的学科是建立12-factor Apps,其中开发实践与交付和运营目标相一致,例如通过使用声明式编程和管理和监控。Spring Cloud通过多种具体方式促进这些开发风格,起点是分布式系统中所有组件需要或需要时轻松访问的一组功能。

许多这些功能都被Spring Boot覆盖,我们在Spring Cloud中建立。更多的由Spring Cloud提供为两个库:Spring Cloud Context和Spring Cloud Commons。Spring Cloud Context为Spring Cloud应用(引导上下文,加密,刷新范围和环境端点)的ApplicationContext提供实用程序和特殊服务。Spring Cloud Commons是不同Spring Cloud实现中使用的一组抽象和常用类(例如Spring Cloud Netflix vs. Spring Cloud Consul)。

如果由于“非法密钥大小”而导致异常,并且您正在使用Sun的JDK,则需要安装Java加密扩展(JCE)无限强度管理策略文件。有关详细信息,请参阅以下链接:

将文件解压缩到JDK / jre / lib / security文件夹(无论您使用的是哪个版本的JRE / JDK x64 / x86)。

注意
Spring Cloud在非限制性Apache 2.0许可证下发布。如果您想为文档的这一部分做出贡献,或者发现错误,请在github中找到项目中的源代码和问题跟踪器

Spring Cloud上下文:应用上下文服务

Spring Boot对如何使用Spring构建应用程序有一个看法:例如它具有常规配置文件的常规位置,以及用于常见管理和监视任务的端点。Spring Cloud建立在此之上,并添加了一些可能系统中所有组件将使用或偶尔需要的功能。

引导应用程序上下文

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

引导上下文使用与主应用程序上下文定位外部配置的不同约定,因此,不使用application.yml(或.properties),您可以使用bootstrap.yml,保持引导和主上下文的外部配置分开。例:

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

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

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

应用程序上下文层次结构

如果您从SpringApplicationSpringApplicationBuilder构建应用程序上下文,则将Bootstrap上下文添加为该上下文的父级。这是Spring的一个功能,即子上下文从其父级继承属性源和配置文件,因此与主要构建相同的上下文(“Spring Cloud Config”相比,“主”应用程序上下文将包含其他属性源。额外的财产来源是:

  • “bootstrap”:如果在Bootstrap上下文中找到任何PropertySourceLocators,则可选CompositePropertySource显示为高优先级,并且它们具有非空属性。一个例子是Spring Cloud Config服务器的属性。有关如何自定义此属性源的内容的说明,请参阅 下文

  • “applicationConfig:[classpath:bootstrap.yml]”(如果Spring配置文件处于活动状态,则为朋友)。如果您有一个bootstrap.yml(或属性),那么这些属性用于配置引导上下文,然后在父设置时将它们添加到子上下文中。它们的优先级低于application.yml(或属性)和作为创建Spring Boot应用程序进程的正常部分添加到子级的任何其他属性源的优先级。有关如何自定义这些属性源的内容的说明,请参阅下文

由于属性源的排序规则,“引导”条目优先,但请注意,这些不包含来自bootstrap.yml的任何数据,其优先级非常低,但可用于设置默认值。

您可以通过简单地设置您创建的任何ApplicationContext的父上下文来扩展上下文层次结构,例如使用自己的界面,或使用SpringApplicationBuilder方便方法(parent()child()sibling())。引导环境将是您创建自己的最高级祖先的父级。层次结构中的每个上下文都将有自己的“引导”属性源(可能为空),以避免无意中将值从父级升级到其后代。层次结构中的每个上下文(原则上)也可以具有不同的spring.application.name,因此如果存在配置服务器,则它也是不同的远程属性源。普通的Spring应用程序上下文行为规则适用于属性解析:子上下文的属性通过名称和属性源名称覆盖父项中的那些(如果子级具有与父级名称相同的属性源,一个来自父母的孩子不包括在孩子中)。

请注意,SpringApplicationBuilder允许您在整个层次结构中共享Environment,但这不是默认的。因此,兄弟情境尤其不需要具有相同的资料或财产来源,尽管它们与父母共享共同点。

改变引导Properties的位置

可以使用spring.cloud.bootstrap.name(默认“引导”)或spring.cloud.bootstrap.location(默认为空)指定bootstrap.yml(或.properties)位置,例如系统属性。这些属性的行为类似于具有相同名称的spring.config.*变体,实际上它们用于通过在其Environment中设置这些属性来设置引导ApplicationContext如果在正在构建的上下文中有一个活动的配置文件(来自spring.profiles.active或通过Environment API),则该配置文件中的属性也将被加载,就像常规的Spring Boot应用程序,例如来自bootstrap-development.properties的“开发”简介。

覆盖远程Properties的值

通过引导上下文添加到应用程序的属性源通常是“远程”(例如从配置服务器),并且默认情况下,不能在本地覆盖,除了在命令行上。如果要允许应用程序使用自己的系统属性或配置文件覆盖远程属性,则远程属性源必须通过设置spring.cloud.config.allowOverride=true(无法在本地设置)来授予其权限。一旦设置了该标志,就会有一些更细微的设置来控制远程属性与系统属性和应用程序本地配置的位置:spring.cloud.config.overrideNone=true覆盖任何本地属性源,spring.cloud.config.overrideSystemProperties=false如果只有系统属性和env var应该覆盖远程设置,而不是本地配置文件。

自定义引导配置

可以通过在org.springframework.cloud.bootstrap.BootstrapConfiguration关键字/META-INF/spring.factories下添加条目来训练引导上下文来执行任何您喜欢的操作。这是用于创建上下文的Spring @Configuration类的逗号分隔列表。您可以在此处创建要用于自动布线的主应用程序上下文的任何bean,并且还有ApplicationContextInitializer类型的@Beans的特殊合同。如果要控制启动顺序(默认顺序为“最后”),可以使用@Order标记类。

警告
添加自定义BootstrapConfiguration时,请注意,您添加的类不是错误的@ComponentScanned到您的“主”应用程序上下文中,可能不需要它们。对于您的@ComponentScan@SpringBootApplication注释配置类尚未涵盖的启动配置类,请使用单独的包名称。

引导过程通过将初始化器注入主SpringApplication实例(即,正常的Spring Boot启动顺序,无论是作为独立应用程序运行还是部署在应用程序服务器中)结束。首先,从spring.factories中找到的类创建一个引导上下文,然后在SpringApplication开始之前将ApplicationContextInitializer类型的所有@Beans添加到主SpringApplication

自定义引导属性源

引导过程添加的外部配置的默认属性源是Config Server,但可以通过将PropertySourceLocator类型的bean添加到引导上下文(通过spring.factories)添加其他源。您可以使用此方法从其他服务器或数据库中插入其他属性。

作为一个例子,请考虑以下微不足道的自定义定位器:

@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,即我们为其提供额外的资源来源。它已经具有正常的Spring Boot提供的资源来源,因此您可以使用这些资源来定位特定于此Environment的属性源(例如,通过将它们锁定在spring.application.name上,如在默认情况下所做的那样Config Server属性源定位器)。

如果你在这个类中创建一个jar,然后添加一个META-INF/spring.factories包含:

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

那么“customProperty”PropertySource将显示在其类路径中包含该jar的任何应用程序中。

环境变化

应用程序将收听一个EnvironmentChangeEvent,并以几种标准方式进行更改(用户可以以常规方式添加ApplicationListeners另外的ApplicationListeners)。当观察到一个EnvironmentChangeEvent时,它将有一个已经更改的键值的列表,应用程序将使用以下内容:

  • 在上下文中重新绑定任何@ConfigurationProperties bean

  • logging.level.*中的任何属性设置记录器级别

请注意,配置客户端不会通过默认轮询查找Environment中的更改,通常我们不建议检测更改的方法(尽管可以使用@Scheduled注释进行设置)。如果您有一个扩展的客户端应用程序,那么最好将EnvironmentChangeEvent广播到所有的实例,而不是让它们轮询更改(例如使用Spring Cloud Bus)。

EnvironmentChangeEvent涵盖了大量的刷新用例,只要您真的可以更改Environment并发布事件(这些API是公开的,部分内核为Spring)。您可以通过访问/configprops端点(普通Spring Boot Actuator功能)来验证更改绑定到@ConfigurationProperties bean。例如,DataSource可以在运行时更改其maxPoolSize(Spring Boot创建的默认DataSource是一个@ConfigurationProperties bean),并且动态增加容量。重新绑定@ConfigurationProperties不会覆盖另一大类用例,您需要更多的控制刷新,而您需要更改为整个ApplicationContext的原子。为了解决这些担忧,我们有@RefreshScope

刷新范围

当配置更改时,标有@RefreshScope的Spring @Bean将得到特殊处理。这解决了状态bean在初始化时只注入配置的问题。例如,如果通过Environment更改数据库URL时DataSource有开放连接,那么我们可能希望这些连接的持有者能够完成他们正在做的工作。然后下一次有人从游泳池借用一个连接,他得到一个新的URL。

刷新范围bean是在使用时初始化的懒惰代理(即当调用一个方法时),并且作用域作为初始值的缓存。要强制bean重新初始化下一个方法调用,您只需要使其缓存条目无效。

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

注意
@RefreshScope工程(技术上)上的@Configuration类,但它可能会导致令人惊讶的行为:例如它并不 意味着所有的@Beans在该类定义本身是@RefreshScope具体来说,任何取决于这些bean的东西都不能依赖它们在刷新启动时被更新,除非它本身在@RefreshScope(在此将重新刷新并重新注入其依赖关系),那么它们将从刷新的@Configuration)重新初始化。

加密和解密

Spring Cloud有一个Environment预处理器,用于在本地解密属性值。它遵循与Config Server相同的规则,并通过encrypt.*具有相同的外部配置。因此,您可以使用{cipher}*格式的加密值,只要有一个有效的密钥,那么在主应用程序上下文获取Environment之前,它们将被解密。要在应用程序中使用加密功能,您需要在您的类路径中包含Spring Security RSA(Maven协调“org.springframework.security:spring-security-rsa”),并且还需要全面强大的JCE扩展你的JVM

如果由于“非法密钥大小”而导致异常,并且您正在使用Sun的JDK,则需要安装Java加密扩展(JCE)无限强度管理策略文件。有关详细信息,请参阅以下链接:

将文件解压缩到JDK / jre / lib / security文件夹(无论您使用的是哪个版本的JRE / JDK x64 / x86)。

端点

对于Spring Boot Actuator应用程序,还有一些额外的管理端点:

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

  • /refresh重新加载引导带上下文并刷新@RefreshScope bean

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

  • /pause/resumeApplicationContext上调用Lifecycle方法(stop()start()

Spring Cloud Commons:普通抽象

诸如服务发现,负载平衡和断路器等模式使自己适用于所有Spring Cloud客户机可以独立于实现(例如通过Eureka或Consul发现)的消耗的共同抽象层。

@EnableDiscoveryClient

Commons提供@EnableDiscoveryClient注释。这通过META-INF/spring.factories查找DiscoveryClient接口的实现。Discovery Client的实现将在org.springframework.cloud.client.discovery.EnableDiscoveryClient键下的spring.factories中添加一个配置类。DiscoveryClient实现的示例是Spring Cloud Netflix EurekaSpring Cloud Consul发现Spring Cloud Zookeeper发现

默认情况下,DiscoveryClient的实现将使用远程发现服务器自动注册本地的Spring Boot服务器。可以通过在@EnableDiscoveryClient中设置autoRegister=false来禁用此功能。

ServiceRegistry

Commons现在提供了一个ServiceRegistry接口,它提供了register(Registration)deregister(Registration)等方法,允许您提供定制的注册服务。Registration是一个标记界面。

@Configuration
@EnableDiscoveryClient(autoRegister=false)
public class MyConfiguration {
    private ServiceRegistry registry;

    public MyConfiguration(ServiceRegistry registry) {
        this.registry = registry;
    }

    // called via some external process, such as an event or a custom actuator endpoint
    public void register() {
        Registration registration = constructRegistration();
        this.registry.register(registration);
    }
}

每个ServiceRegistry实现都有自己的Registry实现。

服务部门自动注册

默认情况下,ServiceRegistry实现将自动注册正在运行的服务。要禁用该行为,有两种方法。您可以设置@EnableDiscoveryClient(autoRegister=false)永久禁用自动注册。您还可以设置spring.cloud.service-registry.auto-registration.enabled=false以通过配置禁用该行为。

服务注册执行器端点

Commons提供/service-registry致动器端点。此端点依赖于Spring应用程序上下文中的Registration bean。通过GET调用/service-registry/instance-status将返回Registration的状态。使用String正文的同一端点的POST将将当前Registration的状态更改为新值。请参阅您正在使用的ServiceRegistry实现的文档,以获取更新状态的允许值和为状态获取的值。

Spring RestTemplate作为负载平衡器客户端

可以自动将RestTemplate配置为使用功能区。要创建负载平衡RestTemplate创建RestTemplate @Bean并使用@LoadBalanced限定符。

警告
通过自动配置不再创建RestTemplate bean。它必须由单个应用程序创建。
@Configuration
public class MyConfiguration {

    @LoadBalanced
    @Bean
    RestTemplate restTemplate() {
        return new RestTemplate();
    }
}

public class MyClass {
    @Autowired
    private RestTemplate restTemplate;

    public String doOtherStuff() {
        String results = restTemplate.getForObject("http://stores/stores", String.class);
        return results;
    }
}

URI需要使用虚拟主机名(即服务名称,而不是主机名)。Ribbon客户端用于创建完整的物理地址。有关 如何设置RestTemplate的详细信息,请参阅 RibbonAutoConfiguration

重试失败的请求

负载平衡RestTemplate可以配置为重试失败的请求。默认情况下,此逻辑被禁用,您可以通过将Spring重试添加到应用程序的类路径中来启用它负载平衡RestTemplate将符合与重试失败请求相关的某些Ribbon配置值。如果要在类路径上使用Spring重试来禁用重试逻辑,则可以设置spring.cloud.loadbalancer.retry.enabled=false您可以使用的属性是client.ribbon.MaxAutoRetriesclient.ribbon.MaxAutoRetriesNextServerclient.ribbon.OkToRetryOnAllOperations请参阅Ribbon文档 ,了解属性的具体内容。

注意
上述示例中的client应替换为您的Ribbon客户端名称。

多个RestTemplate对象

如果你想要一个没有负载均衡的RestTemplate,创建一个RestTemplate bean并注入它。要创建@Bean时,使用@LoadBalanced限定符来访问负载平衡RestTemplate

重要
请注意下面示例中的简单RestTemplate声明中的@Primary注释,以消除不合格的@Autowired注入。
@Configuration
public class MyConfiguration {

    @LoadBalanced
    @Bean
    RestTemplate loadBalanced() {
        return new RestTemplate();
    }

    @Primary
    @Bean
    RestTemplate restTemplate() {
        return new RestTemplate();
    }
}

public class MyClass {
    @Autowired
    private RestTemplate restTemplate;

    @Autowired
    @LoadBalanced
    private RestTemplate loadBalanced;

    public String doOtherStuff() {
        return loadBalanced.getForObject("http://stores/stores", String.class);
    }

    public String doStuff() {
        return restTemplate.getForObject("http://example.com", String.class);
    }
}
提示
如果您看到错误java.lang.IllegalArgumentException: Can not set org.springframework.web.client.RestTemplate field com.my.app.Foo.restTemplate to com.sun.proxy.$Proxy89,请尝试注入RestOperations或设置spring.aop.proxyTargetClass=true

忽略网络接口

有时,忽略某些命名网络接口是有用的,因此可以将其从服务发现注册中排除(例如,在Docker容器中运行)。可以设置正则表达式的列表,这将导致所需的网络接口被忽略。以下配置将忽略“docker0”接口和以“veth”开头的所有接口。

application.yml
spring:
  cloud:
    inetutils:
      ignoredInterfaces:
        - docker0
        - veth.*

您还可以强制使用正则表达式列表中指定的网络地址:

application.yml
spring:
  cloud:
    inetutils:
      preferredNetworks:
        - 192.168
        - 10.0

您也可以强制仅使用站点本地地址。有关更多详细信息,请参阅Inet4Address.html.isSiteLocalAddress()什么是站点本地地址。

application.yml
spring:
  cloud:
    inetutils:
      useOnlySiteLocalInterfaces: true