Spring Cloud入门教程(三):Config配置中心

简介

Config是Spring Cloud中的配置中心,为分布式系统中的微服务应用提供集中化的外部配置支持,配置中心将各个微服务的配置集中管理起来,使得配置文件与项目解耦,配置的维护成本更低,配置更灵活。配置中心分为服务端和客户端,服务端使用Git或SVN以及本地磁盘保存配置文件。

Config Server支持以下几种格式的URL请求:

/{application}/{profile}[/{label}]
/{application}-{profile}.yml
/{label}/{application}-{profile}.yml
/{application}-{profile}.properties
/{label}/{application}-{profile}.properties
/{application}-{profile}.json
/{label}/{application}-{profile}.json

URL中三个参数的定义:
{application}:对应Config Client中spring.application.name参数
{profile}:对应Config Client中spring.profiles.active参数
{label}:对应Config Client中spring.cloud.config.label参数,不传此参数则默认值为:git为master,svn为trunk

Config Client会在启动时以第一种格式的URL请求Config Server,获取自己在配置中心的外部配置文件,并缓存到本地。需要注意的是,第一种格式的URL请求,除了返回指定{profile}的配置文件,同时还会返回default的配置文件,default的配置文件优先级要低一些。

Git仓库

在Github中新建一个仓库,名称为configrepo,在根目录下创建springcloud-user文件夹,在springcloud-user文件夹下创建4个配置文件并提交:
1、springcloud-user.properties

name=defaultman

2、springcloud-user-dev.properties

name=devman

3、springcloud-user-test.properties

name=testman

4、springcloud-user-prod.properties

name=prodman

Config Server

springcloud项目中,新建一个Maven Module,名称为springcloud-config,pom.xml配置如下:

  <parent>
      <groupId>com.itersblog.springcloud</groupId>
      <artifactId>springcloud</artifactId>
      <version>1.0.0</version>
  </parent>
  <artifactId>springcloud-config</artifactId>
  <packaging>jar</packaging>

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

springcloud-config项目中,新增bootstrap.properties,配置如下:

spring.application.name=springcloud-config

logging.pattern.file=%d{yyyy-MM-dd HH:mm:ss.SSS} %5p [%15.15t] %-40.40logger{39} : %X{GLOBAL_REQUEST_ID}%m%n
logging.pattern.console=${logging.pattern.file}

springcloud-config项目中,新增application.properties,配置如下:

server.port=8101

eureka.instance.instanceId=${spring.cloud.client.ipAddress}:${spring.application.name}:${server.port}
eureka.instance.preferIpAddress=true

eureka.client.serviceUrl.defaultZone=http://localhost:8001/eureka/

spring.cloud.config.server.git.uri=git@github.com:itersblog/configrepo.git
spring.cloud.config.server.git.searchPaths={application}

eureka.client.serviceUrl.defaultZone:设置Eureka Server的地址,多个用英文逗号隔开
spring.cloud.config.server.git.uri:git仓库的地址,以.git结尾
spring.cloud.config.server.git.searchPaths:在git仓库根目录的哪个文件夹下查找配置文件

PS:此处git.uri使用的是ssh格式的地址,需要将私钥添加到用户主目录/.ssh文件夹中,并且将对应的公钥添加到github账户的SSH中,否则不能从github拉取配置文件。如果git.uri用http格式的地址,那么需要再添加两个参数,分别是github的用户名和密码:

spring.cloud.config.server.git.username=yourusername
spring.cloud.config.server.git.password=yourpassword

PS:Config Server除了支持Git,同时还支持SVN,将配置参数名中的git改成svn即可,另外,Config Server还支持本地磁盘存储配置文件,这种方式可用性不高,不推荐使用。

springcloud-config项目中,新增CloudConfigApplication.java,代码如下:

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

@EnableEurekaClient:表示启用EurekaClient,将会自动向Eureka Server注册
@EnableConfigServer:表示启用ConfigServer

运行CloudConfigApplication的main方法,启动Config Server(在启动Config Server之前,最好先启动Eureka Server,因为Config Server也是Eureka Client,在Eureka Client启动时,需要向Eureka Server注册,如果此时没有启动Eureka Server,日志中将会看到连接失败的错误信息,下次Eureka Server启动的时候会自动连接上Eureka Server,并向其注册),访问Eureka Server的dashboard,可以看到springcloud-config已经注册成功了。
eureka-dashboard-2.png

Config Client

springcloud项目中,新建一个Maven Module,名称为springcloud-user,这是我们的用户中心,pom.xml配置如下:

  <parent>
      <groupId>com.itersblog.springcloud</groupId>
      <artifactId>springcloud</artifactId>
      <version>1.0.0</version>
  </parent>
  <artifactId>springcloud-user</artifactId>
  <packaging>jar</packaging>

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

springcloud-user项目中,新增bootstrap.properties,配置如下:

spring.application.name=springcloud-user
spring.profiles.active=dev

logging.pattern.file=%d{yyyy-MM-dd HH:mm:ss.SSS} %5p [%15.15t] %-40.40logger{39} : %X{GLOBAL_REQUEST_ID}%m%n
logging.pattern.console=${logging.pattern.file}

eureka.client.serviceUrl.defaultZone=http://localhost:8001/eureka/

spring.cloud.config.discovery.enabled=true
spring.cloud.config.discovery.serviceId=springcloud-config
spring.cloud.config.label=master

spring.profiles.active:设置使用哪个环境的配置
eureka.client.serviceUrl.defaultZone:设置Eureka Server的地址,多个用英文逗号隔开
spring.cloud.config.discovery.enabled:是否启用从Eureka Server查找Config Server服务
spring.cloud.config.discovery.serviceId:Config Server的服务ID,Config Client通过这个服务ID去Eureka Server查找Config Server
spring.cloud.config.label:设置Git或SVN的分支名

PS:Config Client也支持不从Eureka Server查找Config Server服务,直接在配置文件中指定Config Server的地址,但这种方式达不到高可用的标准,不推荐使用。
PS:Config Client中的eureka.client.serviceUrl.defaultZone以及spring.cloud.config.*的配置参数必须要放在bootstrap.properties文件中,不能放在application.properties,因为Config Client启动的时候,先加载bootstrap.properties,再加载配置中心的配置,最后加载application.properties

springcloud-user项目中,新增application.properties,配置如下:

server.port=8201

eureka.instance.instanceId=${spring.cloud.client.ipAddress}:${spring.application.name}:${server.port}
eureka.instance.preferIpAddress=true

springcloud-user项目中,新增CloudUserApplication.java,代码如下:

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

springcloud-user项目中,新增UserController.java,代码如下:

@RestController
@RequestMapping("user")
public class UserController {
    private final Logger logger = LoggerFactory.getLogger(getClass());
    @Autowired
    private Environment env;
    
    @GetMapping("{id}")
    public Map<String,Object> getUser(@PathVariable Long id) {
        long start=System.currentTimeMillis();
        logger.info("request={id="+id+"}");
        Map<String,Object> user=new LinkedHashMap<String,Object>();
        user.put("id", id);
        user.put("name", env.getProperty("name","default"));
        user.put("address", env.getProperty("spring.cloud.client.ipAddress")+":"+env.getProperty("server.port"));
        Map<String,Object> result=new LinkedHashMap<String,Object>();
        result.put("code", 0);
        result.put("message", "OK");
        result.put("user", user);
        logger.info("response="+result+",time="+(System.currentTimeMillis()-start)+"ms");
        return result;
    }
}

运行CloudUserApplication的main方法,启动用户中心(在启动Config Client之前,必须先启动Config Server,并且等Config Server向Eureka Server注册成功之后才能启动Config Client,否则一直提示找不到Config Server,就算之后Config Server启动并注册成功,也会一直找不到Config Server),访问Eureka Server的dashboard,可以看到springcloud-user已经注册成功了。
eureka-dashboard-3.png

在浏览器中访问:http://localhost:8201/user/1,输出:

{
    "code": 0,
    "message": "OK",
    "user": {
        "id": 1,
        "name": "devman"
    }
}

说明springcloud-user已经成功从Config Server中获取到了配置中心的dev环境的配置

spring.profiles.active改成test,再次访问http://localhost:8201/user/1,输出:

{
    "code": 0,
    "message": "OK",
    "user": {
        "id": 1,
        "name": "testman"
    }
}

说明springcloud-user已经成功从Config Server中获取到了配置中心的test环境的配置

运行期间动态更新配置

修改Git中springcloud-user-test.propertiesname=testman-update,提交到Git,再次访问http://localhost:8201/user/1,输出:

{
    "code": 0,
    "message": "OK",
    "user": {
        "id": 1,
        "name": "testman"
    }
}

还是获取的旧的配置参数,说明Config Client只会在启动的时候向Config Server获取配置中心的配置并缓存到本地,如果Config Client启动之后,修改Git仓库的配置,Config Client不会更新配置。这明显不符合要求,如果每次修改配置中心的配置,都要重启应用,那这个配置中心将毫无意义。我们的目的就是在应用运行期间能动态修改配置参数,解决办法如下:
1、pom.xml增加以下依赖,spring-boot-starter-actuator是Spring Boot中的一个监控组件,可以用这个组件在应用运行期间更新应用的配置

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>

2、然后application.properties增加以下配置,关闭权限控制

management.security.enabled=false

因为应用重启了,配置已经更新了,访问http://localhost:8201/user/1,name变成testman-update,现在再次修改Git中springcloud-user-test.properties的name=testman-update2,提交到Git,再次访问http://localhost:8201/user/1,输出:

{
    "code": 0,
    "message": "OK",
    "user": {
        "id": 1,
        "name": "testman-update"
    }
}

说明配置没有更新,然后再POST http://localhost:8201/refresh,输出:

[
    "config.client.version",
    "name"
]

表示这两个参数更新了,再次访问http://localhost:8201/user/1,输出:

{
    "code": 0,
    "message": "OK",
    "user": {
        "id": 1,
        "name": "testman-update2"
    }
}

说明配置已经更新了,现在已经可以在应用运行期间,动态修改配置,但是,每次修改了配置中心的配置都要手动POST刷新,比较繁琐。其实Github提供了Webhook功能,在Git仓库有事件发生时,自动发一个POST请求到指定URL,如图所示:

我们可以利用Webhook功能,在Git仓库有push操作时,发送一个POST请求到应用的刷新地址,这样就可以在修改完配置中心的配置并push后,应用能自动更新。

延伸阅读:Spring Boot配置参数优先级
示例源码:https://github.com/itersblog/springcloud

标签: Spring Cloud入门教程(三):Config配置中心

添加新评论