Spring Cloud 入门 (二): 配置管理

本贴最后更新于 2000 天前,其中的信息可能已经时过境迁

使用 Config Server,您可以在所有环境中管理应用程序的外部属性。客户端和服务器上的概念映射与 Spring EnvironmentPropertySource 抽象相同,因此它们与 Spring 应用程序非常契合,但可以与任何以任何语言运行的应用程序一起使用。随着应用程序通过从开发人员到测试和生产的部署流程,您可以管理这些环境之间的配置,并确定应用程序具有迁移时需要运行的一切。服务器存储后端的默认实现使用 git,因此它轻松支持标签版本的配置环境,以及可以访问用于管理内容的各种工具。很容易添加替代实现,并使用 Spring 配置将其插入

以上是 Spring Cloud 官网对配置服务的描述, 简单阐述一下我的理解。比如我们要搭建一个网站,需要配置数据库连接,指定数据库服务器的 IP 地址,数据库名称,用户名和口令等信息。通常的方法, 我们可以在一个配置文件中定义这些信息,或者开发一个页面专门配置这些东西。只有一个 web 服务器的时候, 很方便。

但假如需要搭建同多台服务器时,当然可以每台服务器做同样配置,但维护和同步会很麻烦。我理解的配置服务至少有两种不同场景:

1). 多个客户使用同一配置: 比如,多台服务器组成的集群,假如后端使用同一数据库,那么每台服务器都是用相同的配置。

2). 不同客户使用不同的配置: 比如典型的场景是,开发,测试,生产使用相同的系统,但使用不同的数据库

如果有个统一的根本配置,是不是就很方便,一个可行的办法是,把这些配置文件放到一个共享存储(比如网络共享盘)中。这样只需要在共享存储修改一个或多个配置文件就可以了。但共享文件的方式受到具体布署环境的限制,很多时候很难达到多台 Web 服务器共享同一个存储硬盘。

共享盘的缺点是资源定位比较困难,Spring Cloud 的解决方案是, 将这些配置文件放到版本管理服务器里面,Spring Cloud 缺省配置使用 GIT 中。所有 Web 服务均从 GIT 中获取这些配置文件。由于 GIT 服务器与具体 Web 服务器之间不需要共享存储, 只要网络可达就行,从而可以实现 Web 服务于配置信息的存放位置的解耦。

Spring Cloud 统一控制应用和 GIT 服务的交互,应用只需要按照 Spring Cloud 的规范配置 GIT 的 URL 即可。 使用 GIT 后,场景 2 和场景 1 的区别仅仅是,场景 2 中不同的 client 使用不同版本的配置文件,但应用但访问的文件看起来是会是同一个。Spring Cloud 的配置服务结构入下图

imagepng

继续上一例 Spring Cloud 入门一. 服务注册 , 让“Hello World”从配置文件 helloworld.properties 读出,内容格式如下
hello=Hello World

其中关键字 hello 的值“Hello World”,就是我们要输出的内容。

一. 创建 config Server

1. 创建 Config Server, maven 工程里面配置 spring-cloud-config-server

<dependency>
        <groupId>org.springframework.cloudgroupId>
        <artifactId>spring-cloud-config-serverartifactId>
<dependency>

完整配置如下:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>com.chry</groupId>
  <artifactId>springcloud.helloworld.config.server</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  <packaging>jar</packaging>
  <name>helloworld.config.server</name>
  <description>Demo Config Server</description>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.5.3.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>
        <!--eureka server -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-eureka</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-eureka-server</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-config-server</artifactId>
        </dependency>
        <!-- spring boot test-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>Dalston.RC1</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

    <repositories>
        <repository>
            <id>spring-milestones</id>
            <name>Spring Milestones</name>
            <url>https://repo.spring.io/milestone</url>
            <snapshots>
                <enabled>false</enabled>
            </snapshots>
        </repository>
    </repositories>

</project>

2. 创建 Config Server,它也是一个 Spring Boot 应用,@EnableConfigServer 注解说明了一个 Config Server。同样我们使用 @EnableEurekaClient 将它注册到服务中心。

package springcloud.helloworld.config.server;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.config.server.EnableConfigServer;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;

@EnableEurekaClient
@EnableConfigServer
@SpringBootApplication
public class ConfigServerApplication {
    public static void main(String[] args) {
        SpringApplication.run(ConfigServerApplication.class, args);
    }
}

3. Config server 的配置文件 appication.yml , 注意配置文件的 url 是 GIT 服务器的仓库地址, searchPaths 配置文件所在的文件夹在仓库中的路径, 在 server 端不需要指定具体配置文件名, 因为具体的配置文件是什么有应用(也就是 client)决定。

eureka:
  client:
    serviceUrl:
      defaultZone: http://localhost:8761/eureka/
server:
  port: 8888

spring:
  cloud:
    config:
      server:
        git:
          uri: https://github.com/keepx/test
          searchPaths: spring-cloud/helloworldConfig
  application:
    name: config-server

4. 启动 config server 后,访问 http://localhost:8888/abc/xyz, 可见如下响应。这个是输出是并没有包括具体配置文件的内容, 这个响应说明,config server 可以正常访问我们配置在 application.yml 中的 GIT 服务

imagepng

这个 URL 是啥意思, 需要解释一下。我们从输出就可以看到 abc 就是 application 的名字,xyz 是 profile 的名字, 注意这里的 abc, xyz 均是随便输入的名字, 并不需要真实存在,config server 这个 REST 接口返回的只是应用名为 abc, profile 名为 xyz 时,GIT 配置环境的结构。

config server 提供的 REST 接口,Spring Cloud 官方文档提供了几个可选 URL 可以是如下几个:

1.  /{application}/{profile}[/{label}]
2.  /{application}-{profile}.yml
3.  /{label}/{application}-{profile}.yml
4.  /{application}-{profile}.properties
5.  /{label}/{application}-{profile}.properties

比如 第三个格式,如果我们在 GIT 版本库中有一个配置文件 spring-cloud/helloworldConfig/config-client-dev.properties. 那么访问 http://localhost:8888/config-client-dev.properties 就可以显示配置文件内容。这个例子中, application 的名字是"config-client"(也是下面我们即将创建的 client), profile 名字是 dev, 文件后缀是.properties

imagepng

本例由于配置了 eureka 服务中心,所以这个 config server 作为一个 eureka client 注册到了 eureka server 中, 可以从 http://localhost:8761 看到我们启动的 config server, 如果不需要注册到服务中心, 也可把这个配置去掉

二. 创建 config client

1. 创建 maven 工程, pom.xml 如下:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.chry</groupId>
    <artifactId>Springcloud.helloworld.config.client</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>Springcloud.helloworld.config.client</name>
    <packaging>jar</packaging>
    <description>Demo Spring Config Client</description>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.5.3.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-eureka</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-config</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>Dalston.RC1</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

    <repositories>
        <repository>
            <id>spring-milestones</id>
            <name>Spring Milestones</name>
            <url>https://repo.spring.io/milestone</url>
            <snapshots>
                <enabled>false</enabled>
            </snapshots>
        </repository>
    </repositories>


</project>

2. 创建一个 spring boot 应用作为 client

package springcloud.helloworld.config.client;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@SpringBootApplication
@RestController
public class ConfigClientApplication {

    public static void main(String[] args) {
        SpringApplication.run(ConfigClientApplication.class, args);
    }

    @Value("${hello}")
    String hello;
    @RequestMapping(value = "/hello")
    public String hello(){
        return hello;
    }
}

这个应用非常简单,就是从 Config Server 中获取配置项 hello 的值,Client Server 向 Config Server 提交 REST 请求后,Config Server 将访问 GIT 服务器,并将取得的配置项 hello 的值返回给 client.

  1. Config client 需要一个应用配置文件, 定义 config Server 的 URL,以及要访问的 GIT 具体分支。这个配置文件是 bootstrap.yml (或者 bootstrap.properties)
spring:
  application:
    name: config-client
  cloud:
    config:
      label: master
      profile: dev
      uri: http://localhost:8888/
server:
  port: 8881

这个配置定义了应用的名字是 config-client(这就是将要用于组装前面 Config Server 一节中题到的 application), profile 采用 dev, GIT 分支用 master。url 是 config server 的地址。那么问题来了,我们似乎没定义配置文件名, 那配置文件名是什么呢? 这点又体现了约定优于配置的思路, 这里 Spring Cloud 约定, 应用的配置文件名以如下方式组成:{application}-{profile}.properties(或者{application}-{profile}.yml)。比如我们这个应用的配置文件就是 config-client-dev.properties. 所以只需要在 GIT 的中创建配置文件 spring-cloud/helloworldConfig/config-client-dev.properties 就可以了, 内容如下:

hello=Hello World from GIT

4. 启动 config-client 应用后, 可以访问 http://locahost/8881/hello, 可以看到,应用本身并没有直接配置 hello 的具体内容, 也没指定具体配置文件,所欲这些都由 spring cloud 框架提交给 config server 了。

imagepng

5. 配置的更新

至此,spring cloud 的配置管理简单示例已经完成,但 client 不能自动感知服务端的变化。 比如,我们修改了 GIT 中的文件内容,但无论如何刷新 client 端的页面,都不能反映配置的变化。

  • Spring

    Spring 是一个开源框架,是于 2003 年兴起的一个轻量级的 Java 开发框架,由 Rod Johnson 在其著作《Expert One-On-One J2EE Development and Design》中阐述的部分理念和原型衍生而来。它是为了解决企业应用开发的复杂性而创建的。框架的主要优势之一就是其分层架构,分层架构允许使用者选择使用哪一个组件,同时为 JavaEE 应用程序开发提供集成的框架。

    940 引用 • 1458 回帖 • 157 关注

相关帖子

欢迎来到这里!

我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。

注册 关于
请输入回帖内容 ...