springcloud-config

背景情况

我们将一个工程,部署到一台机器上运行后,实际上该工程就可以对外提供服务了,但是如果部署服务的机器坏掉后,服务也就不可使用(单点),为了保证服务持续有效,我们会把服务部署到多台机器上,任一台机器坏掉,并不影响其他机器提供服务(集群),偶尔有时候某一个小功能需要上线更新,但又不想使整个服务启停,我们又将把各个服务单独拆分了出来(微服务);在保证服务越来越好的情况下,我们一个服务所使用的机器也越来越多,比如我们在100台机器的集群环境中部署了短信服务,而短信服务所使用的数据库端口为3306,有一天由于数据库升级,端口更改为了3307,这时候我们要做的事情,就是在这一百台机器中,将数据库连接的端口每一台都修改为3307,简直是要了人老命。。。而在spring cloud的解决方案则是有一个分布式的配置中心,来管理所有服务的配置,从而实现一处更改,多处更新。

什么是分布式配置中心

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

实现一个简单的配置中心

Spring Boot 版本为:1.5.13.RELEASE,Spring Cloud版本为:Dalston.SR5。(这里为什么要特别注明版本?因为Spring Boot2.x版本后的配置中心与1.5x版本不一样)

新建一个ConfigServer

pom.xml
<!-- 声明该工程需要使用配置中心服务功能 -->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-config</artifactId>
</dependency>

<!--configServer所需依赖  -->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-config-server</artifactId>
</dependency>

bootstrap.yml
spring:
  application:
    name: config
  profiles:
    active: native  # 配置使用本地储存
  cloud:
    config:
      server:
        native:
          search-locations: file:E:\\gitProjects\\spring-cloud\\springcloud-config\\config\\src\\main\\resources\\properties  # 搜索目录下的properties文件夹下的文件
server:
  port: 7000

search-locations中为什么不用classpath:properties/?因为使用classpath的方式配置中心服务端无法做到及时更新。
为什么使用bootstrap.yml而不使用application.yml?因为bootstrap.yml会先于application.yml加载。
active有native,git,svn三种方式;

该目录下有一个mail-service-dev.yml配置文件,内容是:

name: cxy
spring:
  datasource:
    driver-class-name: com.mysql.jdbc.Driver
#    url: jdbc:mysql://10.8.5.100:3306/acmtc
    url: jdbc:mysql://10.8.3.40:3306/acmtc
    username: root
    password: root

配置文件命名规则:
/{application}/{profile}[/{label}]
/{application}-{profile}.yml
/{label}/{application}-{profile}.yml
/{application}-{profile}.properties
/{label}/{application}-{profile}.properties

App.java
@SpringBootApplication
@EnableConfigServer        // 声明是配置中心服务端
public class App{
    public static void main( String[] args ){
        SpringApplication.run(App.class, args);
    }
}

启动App.java,访问http://localhost:7000/mail-service/dev,可以看到配置信息:

{
  "name": "mail-service",
  "profiles": [
    "dev"
  ],
  "label": null,
  "version": null,
  "state": null,
  "propertySources": [
    {
      "name": "file:E://gitProjects//spring-cloud//springcloud-config//config//src//main//resources//properties/mail-service-dev.yml",
      "source": {
        "name": "cxy",
        "spring.datasource.driver-class-name": "com.mysql.jdbc.Driver",
        "spring.datasource.url": "jdbc:mysql://10.8.3.40:3306/acmtc",
        "spring.datasource.username": "root",
        "spring.datasource.password": "root"
      }
    }
  ]
}

新建一个ConfigClient

pom.xml
<!-- 告诉spring cloud这个工程以web方式运行 -->
<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-jdbc</artifactId>
</dependency>

<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <scope>runtime</scope>
</dependency>
bootstrap.yml
spring:
  application:
    name: mail-service
  cloud:
    config:
      uri: http://localhost:7000/
      profile: dev
server:
  port: 8000
App.java
@SpringBootApplication
@RestController
public class App{
    public static void main( String[] args )
    {
        SpringApplication.run(App.class, args);
    }

    @Autowired
    private Environment environment;

    @Autowired
    private JdbcTemplate jdbcTemplate;

    @RequestMapping(value = "/hi", method = RequestMethod.GET)
    @RefreshScope
    public String hi(){
        return "Hello "+ environment.getProperty("name");
    }

    @RequestMapping(value = "/hiDb", method = RequestMethod.GET)
    public String hiDb(){
        List<User> list = jdbcTemplate.query("select * from user",new Object[]{},new BeanPropertyRowMapper(User.class));
        String account = "";
        if(list!=null&& list.size()>0){
            account = list.get(0).getAccount();
        }
        return "Hello "+ account;
    }
}
DataSourceConfig.java
@Configuration// 配置数据源
public class DataSourceConfig {

	@Bean
	@ConfigurationProperties(prefix = "spring.datasource") // 数据源的自动配置的前缀
	public DataSource dataSource() {
		return DataSourceBuilder.create().build();
	}
}
User.java
public class User {
	private String id;
	private String account;

	public String getId() {
		return id;
	}

	public void setId(String id) {
		this.id = id;
	}

	public String getAccount() {
		return account;
	}

	public void setAccount(String account) {
		this.account = account;
	}
}

启动App.java,可以在启动日志中看到:

2018-10-31 11:34:12.782  INFO 15804 --- [           main] c.c.c.ConfigServicePropertySourceLocator : Fetching config from server at: http://localhost:7000/
2018-10-31 11:34:13.176  INFO 15804 --- [           main] c.c.c.ConfigServicePropertySourceLocator : Located environment: name=mail-service, profiles=[dev], label=null, version=null, state=null
2018-10-31 11:34:13.177  INFO 15804 --- [           main] b.c.PropertySourceBootstrapConfiguration : Located property source: CompositePropertySource [name='configService', propertySources=[MapPropertySource {name='file:E://gitProjects//spring-cloud//springcloud-config//config//src//main//resources//properties/mail-service-dev.yml'}]]

打开浏览器访问http://localhost:8000/hi,则可以看到:Hello cxy,其中cxy为mail-service-dev.yml中配置的值;
打开浏览器访问http://localhost:8000/hiDb,则可以看到:Hello localhostRoot,其中localhostRootmail-service-dev.yml中配置的数据库中查到的值;

至此,我们做到了从配置中心读取配置的功能。

配置信息动态更新

第一步中将配置信息放到了配置中心,所有服务去配置中心里拿取配置,但是如果配置文件有改动,正常情况应该将每一台机器进行重启,以便重新获取配置信息,但是在微服务中,这明显是个耗时耗力的事情,秉持着能省就省的原则,分布式配置中心可以实现不重启刷新配置。

ConfigClient

pom.xml

在原基础上增加

<!-- 客户端刷新配置需要用到 -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
bootstrap.yml

在原基础上增加

management:
  security:
    enabled: false  # 关闭安全校验
App.java
@SpringBootApplication
@RestController
@RefreshScope  		//在需要刷新配置的地方,增加@RefreshScope注解
public class App{
    public static void main( String[] args )
    {
        SpringApplication.run(App.class, args);
    }

    @Autowired
    private Environment environment;

    @Autowired
    private JdbcTemplate jdbcTemplate;

    @RequestMapping(value = "/hi", method = RequestMethod.GET)
    public String hi(){
        return "Hello "+ environment.getProperty("name");
    }

    @RequestMapping(value = "/hiDb", method = RequestMethod.GET)
    public String hiDb(){
        List<User> list = jdbcTemplate.query("select * from user",new Object[]{},new BeanPropertyRowMapper(User.class));
        String account = "";
        if(list!=null&& list.size()>0){
            account = list.get(0).getAccount();
        }
        return "Hello "+ account;
    }
}
DataSourceConfig.java
@Configuration// 配置数据源
public class DataSourceConfig {

	@Bean
	@RefreshScope// 刷新配置文件
	@ConfigurationProperties(prefix = "spring.datasource") // 数据源的自动配置的前缀
	public DataSource dataSource() {
		return DataSourceBuilder.create().build();
	}
}

启动App.java,在浏览器中访问http://localhost:8000/hi,展示Hello cxy
在浏览器中访问http://localhost:8000/hiDb,展示Hello localhostRoot
此时我们更改mail-service-dev.yml配置文件中的值:

#name: cxy
name: cxy32
spring:
  datasource:
    driver-class-name: com.mysql.jdbc.Driver
    url: jdbc:mysql://10.8.5.100:3306/acmtc
#    url: jdbc:mysql://10.8.3.40:3306/acmtc
    username: root
    password: root

通过POST请求访问http://localhost:8000/refresh,得到返回结果:
在这里插入图片描述
可以发现返回结果中有本次修改的内容,分别是spring.datasource.urlname
此时再次访问http://localhost:8000/hi,展示Hello cxy32;访问http://localhost:8000/hiDb,展示Hello root

至此通过配置中心获取配置并动态刷新配置已经成功,但这种方式仍有缺点,就是需要在每一台客户端中执行refresh请求,继续秉持着能省就省的原则,继续改进;

Spring Cloud Bus(消息总线)

SpringCloudBus,大家可以将它理解为管理和传播所有分布式项目中的消息既可,其实本质是利用了MQ的广播机制在分布式的系统中传播消息,目前常用的有Kafka和RabbitMQ。利用bus的机制可以做很多的事情,其中配置中心客户端刷新就是典型的应用场景之一。
在这里插入图片描述

ConfigServer

pom.xml

在原基础上增加:

<!-- 消息总线 -->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-bus-amqp</artifactId>
</dependency>
<!--暴露各种指标 -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>

bootstrap.yml

在原基础上增加mq配置

# mq配置
spring:
  rabbitmq:
    host: localhost
    port: 5672
    username: guest
    password: guest

# 测试阶段关闭安全校验
management:
  security:
    enabled: false

ConfigClient

pom.xml

在原基础上增加:

<!-- 增加消息总线 -->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-bus-amqp</artifactId>
</dependency>

启动App.java,在浏览器中访问http://localhost:8000/hi,展示Hello cxy32
在浏览器中访问http://localhost:8000/hiDb,展示Hello root
此时我们更改mail-service-dev.yml配置文件中的值:

name: cxy
# name: cxy32
spring:
  datasource:
    driver-class-name: com.mysql.jdbc.Driver
#    url: jdbc:mysql://10.8.5.100:3306/acmtc
    url: jdbc:mysql://10.8.3.40:3306/acmtc
    username: root
    password: root

通过POST请求访问http://localhost:7000/bus/refresh,得到返回结果:
在这里插入图片描述
MQ中的消息为:
在这里插入图片描述

此时再次访问http://localhost:8000/hi,展示Hello cxy;访问http://localhost:8000/hiDb,展示Hello localhostRoot

至此spring cloud config 分布式配置中心全部完成。
项目地址:GIT地址

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值