文档章节

spring cloud config 从0到1

twsghxs
 twsghxs
发布于 2017/11/08 14:08
字数 2164
阅读 1355
收藏 40
点赞 5
评论 2

一、简介

1.为什么要配置中心?

随着系统微服务的不断增加,首要考虑的是系统的可伸缩、可扩展性好,随之就是一个配置管理的问题。各自管各自的开发时没什么问题,到了线上之后管理就会很头疼,到了要大规模更新就更烦了。 配置中心就是一个比较好的解决方案,下图就是一个配置中心的解决方案:

常见的配置中心的实现方法有:

  1. 硬编码(缺点:需要修改代码,风险大)
  2. 放在xml等配置文件中,和应用一起打包(缺点:需要重新打包和重启)
  3. 文件系统中(缺点:依赖操作系统等)
  4. 环境变量(缺点:有大量的配置需要人工设置到环境变量中,不便于管理,且依赖平台)

2.spring cloud config

特性

  1. 集中式管理分布式环境下的应用配置
  2. 配置存储默认基于 git 仓库,可进行版本管理
  3. 基于spring环境和Spring应用无缝集成
  4. 提供服务端和客户端支持(java)
  5. 基于restful接口获取配置,客户端可实现多语言
  6. 可集群部署,实现高可用
  7. 配合eureke可实现服务发现,配合cloud bus可实现配置推送更新
  8. 支持数据结构丰富,yml, json, properties

演示图

  1. 配置数据存储在Git等版本仓库中
  2. Config Server获取最新的配置数据
  3. Config Client基于restful接口获取配置

二、初级使用

1.构造config server

(1) pom.xml依赖

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>1.5.6.RELEASE</version>
</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>

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

(2) 程序入口

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

(3) 配置文件

在bootstrap.yml中添加配置:

spring:
  application:
    name: config-server
  cloud:
    config:
      server:
        git:
          uri: http://gitlab.**.cn/java/config-repository.git
          username: ***
          password: ***
          default-label: master
          search-paths: java*,ruby*,go*

server:
  port: 9992

search-paths表示git仓库的存放配置文件的目录

(4) 启动程序

在上面的git仓库中添加一个config-client-test.yml配置文件,配置内容如下:

env: alpha

访问http://localhost:9992/config-client/test/master 可以查看配置信息

表示config server启动成功

{
  "name": "config-client",
  "profiles": Array[1][
    "test"
  ],
  "label": "master",
  "version": "1b28f79de8c4097dc68a4be986d13232662eb036",
  "state": null,
  "propertySources": Array[1][
    {
      "name": "http://gitlab.**.cn/java/config-repository.git/java/config-client-test.yml",
      "source": {
        "env": "alpha"
      }
    }
  ]
}

URL与配置文件的映射关系如下:

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

http://localhost:9992/master/config-client-test.yml

env: alpha

http://localhost:9992/master/config-client-test.json

{
  "env": "alpha"
}

http://localhost:9992/master/config-client-test.properties

env: alpha

2.构造config client

(1) pom.xml依赖

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>1.5.6.RELEASE</version>
</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>

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

(2) 在bootstrap.yml文件中添加相关配置

spring:
  application:
    name: config-client
  profiles:
    active: test
  cloud:
    config:
      label: master
      uri: http://localhost:9992/

(3) 使用配置

启动类

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

Controller类

@RestController
public class EnvController {

  @Value("${env}")
  private String env;

  @RequestMapping(value = "/hi")
  public String hi() {
    return env;
  }
}

(4) 启动观察日志

2017-11-08 17:56:49.730  INFO 3680 --- [  restartedMain] c.c.c.ConfigServicePropertySourceLocator : Fetching config from server at: http://localhost:9992/
2017-11-08 17:56:50.313  INFO 3680 --- [  restartedMain] c.c.c.ConfigServicePropertySourceLocator : Located environment: name=config-client, profiles=[test], label=master, version=06ef59ccd30be2089bc8c7d214b57f0497f1f3f5, state=null
2017-11-08 17:56:50.313  INFO 3680 --- [  restartedMain] b.c.PropertySourceBootstrapConfiguration : Located property source: CompositePropertySource [name='configService', propertySources=[MapPropertySource [name='configClient'], MapPropertySource [name='http://****/config-repository.git/java/config-client-test.yml']]]

(5) 读取配置

访问http://localhost:8080/hi 直接返回

alpha

三、高级使用

1.使用Spring Security进行安全控制

(1) config-server端配置

pom加入依赖:

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

bootstrap.yml文件中加入:

security:
  user:
    name: admin
    password: 123

重新启动后进入页面的时候要求输入用户名和密码

(2) config-client端配置

config-client需要在配置文件中添加验证信息:

spring:
  application:
    name: config-client
  profiles:
    active: test
  cloud:
    config:
      label: master
      uri: http://localhost:9992/
      username: admin
      password: 123

2.配置中心微服务化、集群化

原理图如下所示:

负载均衡可以用nginx,这样spring.cloud.uri配置写域名就行

这里只介绍用spring cloud服务发现组件eureka配置

(1) 准备eureka-server

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

spring:
  application:
    name: eureka-server
server:
  port: 9991
eureka:
  client:
    service-url:
      defaultZone: http://localhost:9991/eureka/
    fetch-registry: false
    register-with-eureka: false

@SpringBootApplication
@EnableEurekaServer
public class EurekaServer {
    public static void main(String[] args) {
        SpringApplication application = new SpringApplication(EurekaServer.class);
        application.run(args);
    }
}

(2) 改造config-server

修改pom文件,添加maven依赖

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

在程序的入口Application类加上@EnableEurekaClient或者@EnableDiscoveryClient注解

配置文件中添加注册地址,将服务注册到eureka-server中

eureka:
  client:
    service-url:
      defaultZone: http://localhost:9991/eureka/

(3) 改造config-client

修改pom文件,添加maven依赖

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

在程序的入口Application类加上@EnableEurekaClient或者@EnableDiscoveryClient注解

修改配置文件,将其注册到eureka-server服务

spring:
  application:
    name: config-client
  profiles:
    active: test
  cloud:
    config:
      label: master
      username: admin
      password: 123
      discovery:
        enabled: true
        service-id: config-server
eureka:
  client:
    service-url:
      defaultZone: http://localhost:9991/eureka/

通过service-id查找config-server服务,可部署多台config-server,实现集群化部署达到高可用

(4) 启动

访问eureka-server的服务器,可以看到config-server和config-client同时都注册在上面:

(5) 读取配置

访问http://localhost:8080/hi 直接返回,表示服务部署成功

alpha

3.刷新配置信息

(1) 单台服务配置刷新

config-client项目

修改pom文件,添加maven依赖,可以调用/refresh接口刷新配置

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

boostrap.yml添加配置,暂时去掉安全认证

management:
  security:
    enabled: false

修改配置引用的地方,添加 @RefreshScope

@RestController
@RefreshScope
public class EnvController {

  @Value("${env}")
  private String env;

  @RequestMapping(value = "/hi")
  public String hi() {
    return env;
  }
}

重新启动 访问http://localhost:8080/hi 返回

alpha

修改git仓库里config-client-test.yml文件

env: alpha123

调用refresh接口

curl -X POST http://localhost:8080/refresh

重新访问返回 alpha123表示配置刷新成功

alpha123

(2) 集群配置刷新

往往我们系统都是集群部署,一台一台调用/refresh接口维护成本太高,这里我们介绍如何使用Spring Cloud Bus实现集群配置的自动刷新,它使用轻量级的消息代理(如RabbitMQ、Kafka)连接分布式系统的节点,广播配置的变化或者其他的管理指令。

(2.1) 安装部署rabbitmq服务(这里省略)

(2.2) 改造config-server和config-client

修改pom文件,添加maven依赖

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-bus-amqp</artifactId>
</dependency>

修改配置文件,添加rabbitmq配置

spring:
  rabbitmq:
    host: localhost
    port: 5672
    username: guest
    password: guest

(2.3) 启动服务

这里我们再启动一个8081端口的config-client服务

访问http://localhost:15672/#/ ,新增了一个Exchange,以及三个queue

因为我们启动了1个config-server、2个config-client 每个服务监听各自的队列消息

(2.4) 刷新配置

先访问http://localhost:8080/hihttp://localhost:8081/hi 返回

alpha123

修改git仓库里config-client-test.yml文件

env: alpha123123

调用config-server的/bus/refresh接口

curl -u admin:123 -X POST http://localhost:9992/bus/refresh

重新访问返回如下,表示集群配置刷新成功

alpha123123

(2.5) 局部刷新配置

调用/bus/refresh,会刷新所有使用spring cloud bus连到rabbitmq的服务,如果需要局部刷新,可通过/bus/refresh的destination参数来定位要刷新的应用程序。

例如 /bus/refresh?destination=config-client:test:8080

这里只刷新8080端口的config-client服务,另一个8081端口的config-client配置没有刷新

我们打断点发现,调用/bus/refresh的服务会向rabbitmq服务发送消息,message的body里有"destinationService":"config-client:test:8080"

因为routing key 是 # ,这样使用spring cloud bus连接rabbitmq的服务都会收到这个消息,

我们发现有个ServiceMatcher类

public class ServiceMatcher implements ApplicationContextAware {
	private ApplicationContext context;
	private PathMatcher matcher;

	@Override
	public void setApplicationContext(ApplicationContext context) throws BeansException {
		this.context = context;
	}

	public void setMatcher(PathMatcher matcher) {
		this.matcher = matcher;
	}

	public boolean isFromSelf(RemoteApplicationEvent event) {
		String originService = event.getOriginService();
		String serviceId = getServiceId();
		return this.matcher.match(originService, serviceId);
	}

	public boolean isForSelf(RemoteApplicationEvent event) {
		String destinationService = event.getDestinationService();
		return (destinationService == null || destinationService.trim().isEmpty() || this.matcher
				.match(destinationService, getServiceId()));
	}

	public String getServiceId() {
		return this.context.getId();
	}

}

重点看isForSelf方法,发现会拿destinationService跟serviceId比较

serviceId实际就是context的id,是由ContextIdApplicationContextInitializer生成的,格式是 name:profiles:index

根据代码可知 name是spring.application.name、index是server.port,如果相匹配就会刷新此服务的配置。

public class ContextIdApplicationContextInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext>, Ordered {

	private static final String NAME_PATTERN = "${spring.application.name:${vcap.application.name:${spring.config.name:application}}}";
	
	private static final String INDEX_PATTERN = "${vcap.application.instance_index:${spring.application.index:${server.port:${PORT:null}}}}";

	private final String name;

	private int order = Ordered.LOWEST_PRECEDENCE - 10;

	public ContextIdApplicationContextInitializer() {
		this(NAME_PATTERN);
	}

	public ContextIdApplicationContextInitializer(String name) {
		this.name = name;
	}

	public void setOrder(int order) {
		this.order = order;
	}

	@Override
	public int getOrder() {
		return this.order;
	}

	@Override
	public void initialize(ConfigurableApplicationContext applicationContext) {
		applicationContext.setId(getApplicationId(applicationContext.getEnvironment()));
	}

	private String getApplicationId(ConfigurableEnvironment environment) {
		String name = environment.resolvePlaceholders(this.name);
		String index = environment.resolvePlaceholders(INDEX_PATTERN);
		String profiles = StringUtils
				.arrayToCommaDelimitedString(environment.getActiveProfiles());
		if (StringUtils.hasText(profiles)) {
			name = name + ":" + profiles;
		}
		if (!"null".equals(index)) {
			name = name + ":" + index;
		}
		return name;
	}
}

四、参考链接

http://tech.lede.com/2017/06/12/rd/server/springCloudConfig/

http://www.cnblogs.com/ityouknow/p/6931958.html

© 著作权归作者所有

共有 人打赏支持
twsghxs
粉丝 3
博文 1
码字总数 2164
作品 0
程序员
加载中

评论(2)

twsghxs
twsghxs

引用来自“uemc”的评论

文章
(2.3) 启动服务
这里我们再启动一个8081端口的config-client服务

访问http://localhost:15672/#/ ,新增了一个Exchange,以及三个queue


端口不是 5672 吗
web管理页面端口是15672,client端通信端口是5672
uemc
uemc
文章
(2.3) 启动服务
这里我们再启动一个8081端口的config-client服务

访问http://localhost:15672/#/ ,新增了一个Exchange,以及三个queue


端口不是 5672 吗
聊聊spring cloud gateway的GatewayFilter

序 本文主要研究一下spring cloud gateway的GatewayFilter GatewayFilter spring-cloud-gateway-core-2.0.0.RC2-sources.jar!/org/springframework/cloud/gateway/filter/GatewayFilter.jav......

go4it
06/09
0
0
聊聊ribbon的超时时间设置

序 本文主要研究一下ribbon的超时时间设置 配置 实例 RibbonClientConfiguration spring-cloud-netflix-ribbon-2.0.0.RELEASE-sources.jar!/org/springframework/cloud/netflix/ribbon/Ribb......

go4it
07/20
0
0
Spring config server

server 添加依赖 添加annotation application.yaml配置文件添加config repo 上面使用的本地文件系统方式进行配置仓库的内容管理,该方式仅用于开发和测试。在生产环境中务必搭建自己的Git配置...

遥借东风
06/13
0
0
SpringCloud负载均衡

Ribbon 配合eureka可以不用配置文件,自动实现负载均衡。 consumer可以根据项目服务名称进行访问,如果多个服务名称一致,自动实现负载均衡。 Feign 一套基于Netflix Feign实现的声明式服务调...

JavionXiong
06/22
0
0
SpringCloud配置中心高可用搭建

本文通过config server连接git仓库来实现配置中心,除了git还可以使用svn或者系统本地目录都行。 引入依赖 spring-cloud-config-server这个就是配置中心server的依赖。 配置中心做到高可用本...

Java技术栈
05/22
0
0
spring boot 之依赖

spring boot 虽然不强制使用特殊的依赖。但是其提供了一些非常高效的依赖。其中最有如下几个: spring-boot-starter-parent spring-boot-starter-data-jpa数据库连接的依赖。 spring-cloud-c...

乾坤刀
05/28
0
0
聊聊spring cloud gateway的RouteLocator

序 本文主要研究一下spring cloud gateway的RouteLocator RouteLocator spring-cloud-gateway-core-2.0.0.RC2-sources.jar!/org/springframework/cloud/gateway/route/RouteLocator.java 其有......

go4it
06/06
0
0
SpringCloud实战7-Config分布式配置管理

分布式环境下的统一配置框架,已经有不少了,比如百度的disconf,阿里的diamand 官方文档对spring Cloud Config的描述如下:   Spring Cloud Config为分布式系统中的外部配置提供服务器和客...

狂小白
05/21
0
0
Spring Cloud 入门教程 - Eureka服务注册与发现

简介 在微服务中,服务注册与发现对管理各个微服务子系统起着关键作用。随着系统水平扩展的越来越多,系统拆分为微服务的数量也会相应增加,那么管理和获取这些微服务的URL就会变得十分棘手,...

乾儿
05/03
0
0
spring cloud config能管理xml文件吗

由于采用了spring boot默认的日志配置logback-spring.xml,先想将其放到github上,被spring cloud config管理,但网上都说spring cloud config只能是application-profie.properties格式。怎么...

shouwangg
06/04
0
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

Spring基础

Spring是什么? Spring是一个开源框架,最早由Rod Johnson创建,它解决的是业务逻辑层和其他各层的松耦合问题。 经过十几年的发展,Spring正在扩展其他的领域,如:移动开发、社交API集成、N...

这很耳东先生
9分钟前
0
0
面试系列-40个Java多线程问题总结

前言 这篇文章主要是对多线程的问题进行总结的,因此罗列了40个多线程的问题。 这些多线程的问题,有些来源于各大网站、有些来源于自己的思考。可能有些问题网上有、可能有些问题对应的答案也...

Ryan-瑞恩
22分钟前
0
0
微信分享的细节

分享的缩略图要求: 一、图片大小小于32k 二、图片的尺寸为 宽度 :128px 高度:128px 分享title 和 description 出现金额等 以上情况存在会导致触发分享按钮 但是页面没有反应...

Js_Mei
28分钟前
0
0
【2018.07.23学习笔记】【linux高级知识 Shell脚本编程练习】

1、编写shell脚本,计算1-100的和; #!/bin/bashsum=0for i in `seq 1 100`do sum=$[$sum+$i]doneecho $sum 2、编写shell脚本,要求输入一个数字,然后计算出从1到输入数字的和,要求...

lgsxp
30分钟前
0
0
xss攻防浅谈

导读 XSS (Cross-Site Script) 攻击又叫跨站脚本攻击, 本质是一种注入攻击. 其原理, 简单的说就是利用各种手段把恶意代码添加到网页中, 并让受害者执行这段脚本. XSS能做用户使用浏览器能做的...

吴伟祥
30分钟前
0
0
js回调的一次应用

function hideBtn(option) { if (option == 1) { $("#addBtn").hide(); $("#addSonBtn").hide(); }}$("body").on("click", "#selectBtn", function () {......

晨猫
37分钟前
0
0
C++_读写ini配置文件

1.WritePrivateProfileString:写配置文件 WritePrivateProfileString 函数的定义形式为: BOOL WritePrivateProfileString(LPCTSTR lpAppName, LPCTSTR lpKeyName, LPCTSTR lpString, LPCTST......

一个小妞
37分钟前
0
0
通往阿里,BAT的50+经典Java面试题及答案解析(上)

Java是一个支持并发、基于类和面向对象的计算机编程语言。下面列出了面向对象软件开发的优点: 代码开发模块化,更易维护和修改。 代码复用。 增强代码的可靠性和灵活性。 增加代码的可理解性...

Java大蜗牛
37分钟前
1
0
数据库两大神器【索引和锁】

前言 只有光头才能变强 索引和锁在数据库中可以说是非常重要的知识点了,在面试中也会经常会被问到的。 本文力求简单讲清每个知识点,希望大家看完能有所收获 声明:如果没有说明具体的数据库...

Java3y
41分钟前
0
0
Application Express安装

Application Express安装文档 数据库选择和安装 数据库选择 Oracle建议直接12.2.0.1.0及以上的版本,12.1存在20618595bug(具体可参见官方文档) Oracle 12c 中安装oracle application expr...

youfen
53分钟前
0
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部