spring cloud config 从0到1

一、简介

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

转载于:https://my.oschina.net/twsghxs/blog/1568992

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
从0到1搭建Spring Cloud项目可以按照以下步骤进行: 1. 首先,了解Spring Cloud是什么。Spring Cloud是一个开源的微服务框架,可以帮助开发人员快速构建和部署云原生应用程序。它提供了一套丰富的组件,包括服务注册与发现、负载均衡、断路器、配置管理等,可以帮助开发人员轻松构建可伸缩、弹性和可靠的分布式系统。 2. 接下来,创建一个新的Spring Cloud项目。可以使用Spring Initializr(https://start.spring.io/)来初始化一个新的Spring Boot项目。在这个项目中,可以选择集成所需的Spring Cloud组件,例如Spring Cloud Zuul、Spring Cloud Eureka、Spring Cloud Config等等。根据项目的需求,选择合适的组件进行集成。 3. 在项目中创建服务提供者和服务调用者。可以根据实际需求创建多个微服务,每个微服务负责处理特定的业务逻辑。例如,可以创建一个名为cloud-payment的服务提供者工程,和一个名为cloud-order的服务调用者工程。服务提供者负责提供具体的服务,服务调用者则通过调用提供者的API来消费服务。 4. 集成其他相关组件。根据项目需求,可以进一步集成其他Spring Cloud组件,如Spring Cloud Zipkin用于分布式跟踪,以及网关的熔断和负载均衡等。 总结起来,从0到1搭建Spring Cloud项目的步骤可以概括为:了解Spring Cloud -> 创建Spring Cloud项目 -> 创建服务提供者和服务调用者 -> 集成其他相关组件。<span class="em">1</span><span class="em">2</span><span class="em">3</span><span class="em">4</span> #### 引用[.reference_title] - *1* [springcloud项目Demo](https://download.csdn.net/download/m0_69665204/87381048)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 33.333333333333336%"] - *2* *4* [SpringCloud 入门实战(二)-SpringCloud项目从0到1搭建](https://blog.csdn.net/weixin_47061482/article/details/125673913)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 33.333333333333336%"] - *3* [【微服务笔记23】使用Spring Cloud微服务组件从0到1搭建一个微服务工程](https://blog.csdn.net/qq_39826207/article/details/130393617)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 33.333333333333336%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值