Spring Cloud Config

一、概念

1,简介

  微服务意味着要将单体应用中的业务拆分为一个个子服务,每个服务的粒度相对较小,因此系统中会出现大量的服务。由于每个服务都需要必要的配置信息才能运行,所以一套集中式的、动态的配置管理设施是必不可少的。

2,作用

  • 集中管理配置文件
  • 不同环境不同配置,动态化的配置更新,分环境部署比如dev/test/prod/beta/release
  • 运行期间动态调整配置,不再需要在每个服务部署的机器上编写配置文件,服务会向配置中心统一拉取配置自己的信息
  • 当配置发生变动时,服务不需要重启即可感知配置的变化并应用新的配置(post、curl访问刷新)

二、案例

源码:cloud-config

1,配置SpringCloud Config Server

源码:cloud-config-center3344

  添加依赖:
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-config-server</artifactId>
</dependency>
  配置application.yml文件:
server:
  port: 3344
spring:
  application:
    name: cloud-config-center
  cloud:
    config:
      server:
        git:
          uri:  https://gitee.com/xiaocheng0902/spring-cloud.git #填写你自己的github路径
          search-paths:
            - spring-cloud-config
      label: master
eureka:
  client:
    service-url:
      defaultZone:  http://localhost:7001/eureka
  启动类中添加注解:@EnableConfigServer
  访问:http://localhost:3344 + ...
/{application}/{profile}[/{label}]
/{application}-{profile}.yml
/{label}/{application}-{profile}.yml  
/{application}-{profile}.properties
/{label}/{application}-{profile}.properties

2,配置SpringCloud Config Client

源码:cloud-config-client3355

  pom文件配置
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-config</artifactId>
</dependency>

  bootstrap.yaml文件

spring:
  application:
    name: config-client
  cloud:
    config:
      label: master #分支分支名称
      name: config #配置文件名称
      profile: dev #配置后缀名称  上述三个综合:master分支上config-dev.yml的配置文件被读取为  http://localhost:3344/master/config-dev.yml
      uri: http://localhost:3344 #配置中心地址

  启动类

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

问题

1,修改gitee上的配置文件内容
2,刷新3344,发现ConfigServer配置中心立刻响应
3,刷新3355,发现ConfigServer客户端没有任何响应(除非重启或重新加载)

3,Config客户端之动态刷新

源码:cloud-config-client3355

   pom文件添加

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

   bootstrap.yaml中添加暴露端点

management:
  endpoints:
    web:
      exposure:
        include: "*"

   需要引用gitee配置中心的上添加注解:@RefreshScope

   gitee上文件更新后,发送请求:curl -X POST "http://localhost:3355/actuator/refresh"

问题:

如果有多个微服务客户端3355/3366/3377...那么是否每次修改都需要每个未付手动刷新?

三、SpringCloud配置动态刷新

安装erlang和rabbitmq

http://erlang.org/download/otp_win64_21.3.exe  #直接下一步就行
https://dl.bintray.com/rabbitmq/all/rabbitmq-server/3.7.14/rabbitmq-server-3.7.14.exe #直接下一步
#安装完成之后进入rabbitmq安装的sbin目录执行命令,之后就可以在控制台启动了http://localhost:15672/
rabbitmq-plugins enable rabbitmq_management

1,采用SpringCloud Bus刷新

a)服务端

  pom中添加

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-bus-amqp</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-config-server</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
    <groupId>com.xcc</groupId>
    <artifactId>cloud-api-commons</artifactId>
    <version>${project.version}</version>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>

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

  bootstrap.yaml中添加

server:
  port: 3344
spring:
  application:
    name: cloud-config-center
  cloud:
    config:
      server:
        git:
          uri:  https://gitee.com/xiaocheng0902/spring-cloud.git #填写你自己的github路径
          search-paths:
            - spring-cloud-config
      label: master
  rabbitmq:
    host: localhost
    port: 5672
    username: guest
    password: guest

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

management:
  endpoints:
    web:
      exposure:
        include: 'bus-refresh'

  application应用类为

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

b)客户端

  pom文件

<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>
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-config</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>

  bootstrap.yaml

server:
  port: 3355

spring:
  application:
    name: config-client
  cloud:
    config:
      label: master #分支分支名称
      name: config #配置文件名称
      profile: dev #配置后缀名称  上述三个综合:master分支上config-dev.yml的配置文件被读取为  http://localhost:3344/master/config-dev.yml
      uri: http://localhost:3344 #配置中心地址
  rabbitmq:
    host: localhost
    port: 5672
    username: guest
    password: guest
eureka:
  client:
    service-url:
      defaultZone: http://eureka7001.com:7001/eureka

#暴露端点
management:
  endpoints:
    web:
      exposure:
        include: "*"

  application类中

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

  引用文件的类

@RestController
@RefreshScope
public class ConfigClientController {
    @Value("${config.version}")
    private String configVersion;
    @GetMapping("/configVersion")
    public String getConfigVersion(){
        return configVersion;
    }
}

2,采用webhook全自动刷新

四、Cloud Stream

  SpringCloud Stream是一个构建消息驱动微服务的框架

     

1,常用API

组成说明
Middleware 中间件,目前只支持RabbitMQ和Kafka
Binder Binder是应用于消息中间件之间的封装,目前实行了Kafka和RabbitMQ的Binder,通过Binder可以很方便的连接中间件,可以动态的改变消息类型(对应于Kafka的topic,RabbitMQ的exchange),这些都可以通过配置文件来实现
@Input 注解标识输入通道,通过该输入通道接收到的消息进入应用程序
@Output 注解标识输出通道,发布的消息将通过该通道离开应用程序
@StreamListener 监听队列,用于消费者的队列的消息接收
@EnableBinding 指信道channel和exchange绑定在一起

2,生产者

源码:cloud-stream-rabbitmq-provider8801

  pom文件

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-stream-rabbit</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>

  yaml文件

server:
  port: 8801
spring:
  application:
    name: cloud-stream-provider
  cloud:
    stream:
      binders: # 在此处配置要绑定的rabbitmq的服务信息;
        defaultRabbit: # 表示定义的名称,用于于binding整合
          type: rabbit # 消息组件类型
          environment: # 设置rabbitmq的相关的环境配置
            spring:
              rabbitmq:
                host: localhost
                port: 5672
                username: guest
                password: guest
      bindings: # 服务的整合处理
        output: # 这个名字是一个通道的名称 通道1
          destination: studyExchange # 表示要使用的Exchange名称定义
          content-type: application/json # 设置消息类型,本次为json,文本则设置“text/plain”
          default-binder: defaultRabbit  # 设置要绑定的消息服务的具体设置 与定义的binders对应
        output1: # 这个名字是一个通道的名称 通道2
          destination: studyExchange1 # 表示要使用的Exchange名称定义
          content-type: application/json # 设置消息类型,本次为json,文本则设置“text/plain”
          default-binder: defaultRabbit  # 设置要绑定的消息服务的具体设置 与定义的binders对应
        output2: # 这个名字是一个通道的名称 通道3
          destination: studyExchange2 # 表示要使用的Exchange名称定义
          content-type: application/json # 设置消息类型,本次为json,文本则设置“text/plain”
          default-binder: defaultRabbit  # 设置要绑定的消息服务的具体设置 与定义的binders对应
eureka:
  client: # 客户端进行Eureka注册的配置
    service-url:
      defaultZone: http://localhost:7001/eureka
  instance:
    lease-renewal-interval-in-seconds: 2 # 设置心跳的时间间隔(默认是30秒)
    lease-expiration-duration-in-seconds: 5 # 如果现在超过了5秒的间隔(默认是90秒)
    instance-id: send-8801.com  # 在信息列表时显示主机名称
    prefer-ip-address: true     # 访问的路径变为IP地址

  启动类

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

  定义source源

/**
 * 自定义mq的source数据源
 */
public interface MqMessageSource {

    String OUT_PUT = "output";
    String OUT_PUT1 = "output1";
    String OUT_PUT2 = "output2";

    @Output(OUT_PUT)
    MessageChannel output();

    @Output(OUT_PUT1)
    MessageChannel output1();

    @Output(OUT_PUT2)
    MessageChannel output2();

}
View Code

  发送消息

@EnableBinding(MqMessageSource.class) //定义消息的推送管道
public class MessageProviderImpl implements IMessageProvider {

    @Resource(name = MqMessageSource.OUT_PUT)
    private MessageChannel output;
    @Resource(name = MqMessageSource.OUT_PUT1)
    private MessageChannel output1;
    @Resource(name = MqMessageSource.OUT_PUT2)
    private MessageChannel output2;

    @Override
    public String send() {
        String serial = IdUtil.simpleUUID();
        boolean send = output.send(MessageBuilder.withPayload(serial).build());
        System.out.println("output******************serial: "+serial+"	发送情况"+send);
        return serial;
    }

    @Override
    public String send1() {
        String serial = IdUtil.simpleUUID();
        boolean send = output1.send(MessageBuilder.withPayload(serial).build());
        System.out.println("output1******************serial: "+serial+"	发送情况"+send);
        return serial;
    }

    @Override
    public String send2() {
        String serial = IdUtil.simpleUUID();
        boolean send = output2.send(MessageBuilder.withPayload(serial).build());
        System.out.println("output2******************serial: "+serial+"	发送情况"+send);
        return serial;
    }

}
View Code

3,消费者

源码:cloud-stream-rabbitmq-consumer8803

  pom文件

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-stream-rabbit</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>

  yam文件

server:
  port: 8803

spring:
  application:
    name: cloud-stream-consumer
  cloud:
    stream:
      binders: # 在此处配置要绑定的rabbitmq的服务信息;
        defaultRabbit: # 表示定义的名称,用于于binding整合
          type: rabbit # 消息组件类型
          environment: # 设置rabbitmq的相关的环境配置
            spring:
              rabbitmq:
                host: localhost
                port: 5672
                username: guest
                password: guest
      bindings: # 服务的整合处理
        input: # 这个名字是一个通道的名称
          destination: studyExchange # 表示要使用的Exchange名称定义
          content-type: application/json # 设置消息类型,本次为json,文本则设置“text/plain”
          default-binder: defaultRabbit  # 设置要绑定的消息服务的具体设置 与定义的binders对应
          group: xcc01 #消费者组,防止消息重复消费和消息的丢失
        input1: # 这个名字是一个通道的名称
          destination: studyExchange1 # 表示要使用的Exchange名称定义
          content-type: application/json # 设置消息类型,本次为json,文本则设置“text/plain”
          default-binder: defaultRabbit  # 设置要绑定的消息服务的具体设置 与定义的binders对应
          group: xcc01
        input2: # 这个名字是一个通道的名称
          destination: studyExchange2 # 表示要使用的Exchange名称定义
          content-type: application/json # 设置消息类型,本次为json,文本则设置“text/plain”
          default-binder: defaultRabbit  # 设置要绑定的消息服务的具体设置 与定义的binders对应
          group: xcc01

eureka:
  client: # 客户端进行Eureka注册的配置
    service-url:
      defaultZone: http://localhost:7001/eureka
  instance:
    lease-renewal-interval-in-seconds: 2 # 设置心跳的时间间隔(默认是30秒)
    lease-expiration-duration-in-seconds: 5 # 如果现在超过了5秒的间隔(默认是90秒)
    instance-id: receive-8803.com  # 在信息列表时显示主机名称
    prefer-ip-address: true     # 访问的路径变为IP地址

  启动类

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

  自定义管道sink

/**
 * 自定义mq的管道输出
 */
public interface MqMessageSink {

    String IN_PUT = "input";
    String IN_PUT1 = "input1";
    String IN_PUT2 = "input2";

    @Input(IN_PUT)
    SubscribableChannel input();

    @Input(IN_PUT1)
    SubscribableChannel input1();

    @Input(IN_PUT2)
    SubscribableChannel input2();

}
View Code

  消息消费

@Component
@EnableBinding(MqMessageSink.class)
public class ReceiveMessageListenerController {

    @Value("${server.port}")
    private String serverPort;

    @StreamListener(MqMessageSink.IN_PUT)
    public void input(Message<String>message) {
        System.out.println("input 消费者2号,接受:"+message.getPayload()+"	 port:"+serverPort);
    }

    @StreamListener(MqMessageSink.IN_PUT1)
    public void input1(Message<String>message) {
        System.out.println("input1 消费者2号,接受:"+message.getPayload()+"	 port:"+serverPort);
    }

    @StreamListener(MqMessageSink.IN_PUT2)
    public void input2(Message<String>message) {
        System.out.println("input2 消费者2号,接受:"+message.getPayload()+"	 port:"+serverPort);
    }

}
View Code
原文地址:https://www.cnblogs.com/bbgs-xc/p/13805931.html