菜鸟的springcloud学习总结(六):服务配置

  • 说明
  • 一、服务配置
  • 二、Spring Cloud Config
  • (1)Config服务端
  • (2)仓库上配置文件命名及访问
  • (3)Config客户端
  • 三、Spring Cloud Bus
  • (1)Config服务端
  • (2)Config客户端
  • 四、Spring Cloud Stream
  • (1)生产者
  • (2)消费者


说明

更新时间:2020/10/04 16:12,更新到了Spring Cloud Stream

本文主要对springcloud中的服务配置进行学习与记录,主要偏向于实战,本文会持续更新,不断地扩充

本文仅为记录学习轨迹,如有侵权,联系删除

一、服务配置

springcloud应用启动不打印logback日志 springcloud日志配置_配置文件


在分布式系统中,由于服务数量巨多,为了方便服务配置文件统一管理,实时更新,所以需要分布式配置中心组件。一个配置中心提供的核心功能,提供服务端和客户端支持,集中管理各环境的配置文件,配置文件修改之后,可以快速的生效,可以进行版本管理,支持大的并发查询,支持各种语言等

二、Spring Cloud Config

Spring Cloud Config项目是一个解决分布式系统的配置管理方案。它包含了Client和Server两个部分,server提供配置文件的存储、以接口的形式将配置文件的内容提供出去,client通过接口获取数据、并依据此数据初始化自己的应用。Spring cloud使用git或svn存放配置文件,默认情况下使用git,我们先以git为例做一套示例。

下面采用git加码云的方式进行演示

前期准备
先在码云上面创建一个仓库,用于存放分布式的配置文件,并且创建对应的几个yml配置文件,config-dev.yml、config-pro.yml、config-test.yml分别表示开发环境、生产环境和测试环境的配置文件

springcloud应用启动不打印logback日志 springcloud日志配置_Stream_02

(1)Config服务端

创建Config服务端对应的子模块cloud-config-server-3344,引入pom坐标依赖

<dependencies>
        <!--引入公共包-->
        <dependency>
            <groupId>com.zsc</groupId>
            <artifactId>cloud-api-commons</artifactId>
            <version>${project.version}</version>
        </dependency>

        <!--spring cloud config 服务端包-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-config-server</artifactId>
        </dependency>


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

        <!--springboot starter启动器-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <!--单元测试-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>

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


    </dependencies>

重点是spring cloud config 服务端包,然后配置yml文件

server:
  port: 3344

spring:
  application:
    name: cloud-config-server3344
  cloud:
    config:
      server:
        git:
          #码云上面的配置的仓库地址,公有的不用设置密码
          uri: https://gitee.com/strong_rookie/spring-cloud-config.git

          #搜索目录
          search-paths:
            - Spring Cloud Config
      #读取分支
      label: master

#注册进eureka
eureka:
  client:
    service-url:
      defaultZone: http://eureka7001.com:7001/eureka/

主启动类,注意加上EnableConfigServer注解

springcloud应用启动不打印logback日志 springcloud日志配置_配置文件_03


之后就可以访问了,由于这里还注册了eureka,所以eureka服务注册中心也得打开

springcloud应用启动不打印logback日志 springcloud日志配置_Bus_04


之后就可以访问了http://localhost:3344/master/config-pro.yml

springcloud应用启动不打印logback日志 springcloud日志配置_Config_05

(2)仓库上配置文件命名及访问

http请求地址和资源文件映射如下:

/{application}/{profile}[/{label}]

/{application}-{profile}.yml

/{label}/{application}-{profile}.yml

/{application}-{profile}.properties

/{label}/{application}-{profile}.properties

仓库上的配置文件可以按照上面的任一方式命名,上面的项目用的是第二种命名方式,例如:config-dev.yml

上面的命名方式决定了路径的访问方式,例如:config-dev.yml,访问时则是http://localhost:3344/master/config-dev.yml路径

springcloud应用启动不打印logback日志 springcloud日志配置_spring_06

(3)Config客户端

创建Config子模块cloud-config-client-3355,引入依赖

<dependencies>
        <!--引入公共包-->
        <dependency>
            <groupId>com.zsc</groupId>
            <artifactId>cloud-api-commons</artifactId>
            <version>${project.version}</version>
        </dependency>

        <!-- spring cloud config 客户端包 -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-config</artifactId>
        </dependency>

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

        <!--springboot starter启动器-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <!--单元测试-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>

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


    </dependencies>

重点是spring cloud config 客户端包,然后创建配置文件bootstrap.yml

server:
  port: 3355

spring:
  application:
    name: cloud-config-client3355
  cloud:
    config:
      label: master  #分支名称
      name: config   #配置文件的名称
      profile: dev   #读取后缀名称
      uri: http://localhost:3344/  #配置config中心地址
      #上面的配置解释为:master分支上config-dev.yml的配置文件被读取,http://localhost:3344/master/config-dev.yml


#注册进eureka
eureka:
  client:
    service-url:
      defaultZone: http://eureka7001.com:7001/eureka/

#暴露监控端点,实现配置文件实时更新
management:
  endpoints:
    web:
      exposure:
        include: "*"

这里配置了配置文件实时更新,这样的话假设仓库上的配置文件修改了,也能实现实时的更新,当然,这之间还有一个小步骤

关于bootstrap.yml配置文件

springcloud应用启动不打印logback日志 springcloud日志配置_配置文件_07


然后是主启动类

springcloud应用启动不打印logback日志 springcloud日志配置_spring_08


然后是业务类,客户端通过接口的方式的将获取配置文件的内容,就是以rest风格将配置对外暴露

springcloud应用启动不打印logback日志 springcloud日志配置_spring_09


代码

@RestController
@RefreshScope//实现配置文件的实时更新
public class ConfigClientController {

    @Value("${server.version}")
    private String serverVersion;

    @GetMapping("/getServerVersion")
    public String getServerVersion(){
        return serverVersion;
    }
}

注意controller里面的类要实现实时的更新配置文件需要在每一个controller类上加一个刷新的注解

springcloud应用启动不打印logback日志 springcloud日志配置_Config_10


启动项目进行测试

springcloud应用启动不打印logback日志 springcloud日志配置_Stream_11


访问接口http://localhost:3355/getServerVersion,可以获取配置文件的内容

springcloud应用启动不打印logback日志 springcloud日志配置_Config_12

如何实现实时更新配置文件内容,首先在远程仓库更新一下配置文件

springcloud应用启动不打印logback日志 springcloud日志配置_spring_13


再访问接口访问接口http://localhost:3355/getServerVersion发现还是version2.0,这是因为还有一个步骤,就是需要先发送一个post请求如下,用于提醒客户端我已经更新了配置文件

springcloud应用启动不打印logback日志 springcloud日志配置_spring_14


代码

curl -X POST "http://localhost:3355/actuator/refresh"

再访问接口http://localhost:3355/getServerVersion

springcloud应用启动不打印logback日志 springcloud日志配置_配置文件_15


当然这种是半自动化配置,虽然当修改完配置文件后,可以用脚本实现自动发送post以达到实时更新的目的

三、Spring Cloud Bus

上面的项目实现了客户端的配置的刷新,但是还有问题,当客户端越来越多的情况下,远程仓库上的配置改变后,客户端要得到最新的配置文件内容,则需要每一个客户端都要发送一个post请求

springcloud应用启动不打印logback日志 springcloud日志配置_Config_16


这样的话,当有三四十个客户端的情况下,就会显得很麻烦,所以下面就有Spring Cloud Bus消息总线,用来实现一次广播,实现所有的客户端刷新

简单介绍Spring Cloud Bus
SpringCloud Bus使用轻量级消息代理将分布式系统的节点连接起来。然后可以使用此代理广播状态更改(例如配置更改)或其他管理指令。本文结合RabbitMQ+码云实现上面Config配置中心的自动刷新。

它的广播方式有两种,这里主要采用下面的广播方式

springcloud应用启动不打印logback日志 springcloud日志配置_Config_17


远程仓库上的配置文件修改之后,首先由服务端Config服务端发送一个post请求,Spring Cloud Bus接收到后,通过广播的方式将消息发送给所有的Config客户端,客户端实现配置文件的刷新为什么被称为总线?

springcloud应用启动不打印logback日志 springcloud日志配置_Stream_18


实战

下面直接开始实战,为了能看到广播的效果,必须要再创建一个Config客户端cloud-config-client-3366,内容基本跟cloud-config-client-3355一样,这里还需要先安装mq消息队列,并且可以访问

springcloud应用启动不打印logback日志 springcloud日志配置_spring_19

(1)Config服务端

在cloud-config-server-3344引入对应的坐标依赖

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

修改配置文件,主要增加了mq的配置和bus刷新配置的端点

springcloud应用启动不打印logback日志 springcloud日志配置_Bus_20

代码如下

server:
  port: 3344

spring:
  application:
    name: cloud-config-server3344
  cloud:
    config:
      server:
        git:
          #码云上面的配置的仓库地址,公有的不用设置密码
          uri: https://gitee.com/strong_rookie/spring-cloud-config.git
          #搜索目录
          search-paths:
            - Spring Cloud Config
      #读取分支
      label: master
  #添加mq配置
  rabbitmq:
    host: 39.96.22.34
    port: 5675
    username: guest
    password: guest
    virtual-host: /
#mq相关配置,暴露bus刷新配置的端点
management:
  endpoints:
    web:
      exposure:
        include: 'bus-refresh'


#注册进eureka
eureka:
  client:
    service-url:
      defaultZone: http://eureka7001.com:7001/eureka/

(2)Config客户端

客户端的配置文件修改,以3355项目为例,主要增加下面的坐标

springcloud应用启动不打印logback日志 springcloud日志配置_配置文件_21


代码

<!-- 添加消息总线RabbitMQ支持 -->
        <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>

修改配置文件

springcloud应用启动不打印logback日志 springcloud日志配置_Stream_22


代码

server:
  port: 3355

spring:
  application:
    name: cloud-config-client3355
  cloud:
    config:
      label: master  #分支名称
      name: config   #配置文件的名称
      profile: dev   #读取后缀名称
      uri: http://localhost:3344/  #配置config中心地址
      #上面的配置解释为:master分支上config-dev.yml的配置文件被读取,http://localhost:3344/master/config-dev.yml


#添加mq配置
  rabbitmq:
    host: 39.96.22.34
    port: 5675
    username: guest
    password: guest
    virtual-host: /

#注册进eureka
eureka:
  client:
    service-url:
      defaultZone: http://eureka7001.com:7001/eureka/

#暴露监控端点,实现配置文件实时更新
management:
  endpoints:
    web:
      exposure:
        include: "*"

注意:对3366项目也做同样的操作

启动项目

springcloud应用启动不打印logback日志 springcloud日志配置_配置文件_23


访问3355和3366项目,两个项目获取到的配置文件数据都是version3.0

springcloud应用启动不打印logback日志 springcloud日志配置_配置文件_24


现在在远程仓库上修改配置文件,改为4.0

springcloud应用启动不打印logback日志 springcloud日志配置_Stream_25


此时所有的服务端和客户端还没有刷新,访问3355和3366项目接口,仍然是3.0

springcloud应用启动不打印logback日志 springcloud日志配置_spring_26


此时只需要Config服务端发送一个post请求即可通过广播的方式对所有的客户端进行刷新

springcloud应用启动不打印logback日志 springcloud日志配置_spring_27


代码

curl -X POST "http://localhost:3344/actuator/bus-refresh"

下面重新访问3355和3366项目,发现两个都进行了更新

springcloud应用启动不打印logback日志 springcloud日志配置_Bus_28

此外还可以对某一个客户端进行更新,另一个则不更新,重新修改仓库上的配置文件为5.0

springcloud应用启动不打印logback日志 springcloud日志配置_spring_29


现在更新3355的配置,3366不更新

springcloud应用启动不打印logback日志 springcloud日志配置_Stream_30


springcloud应用启动不打印logback日志 springcloud日志配置_Bus_31

代码

curl -X POST "http://localhost:3344/actuator/bus-refresh/cloud-config-client3355:3355"

参数:
cloud-config-client3355:3355:  是3355项目yml配置文件中的spring.application.name,3355为对应端口

springcloud应用启动不打印logback日志 springcloud日志配置_Stream_32

四、Spring Cloud Stream

简介
简单理解一下定义,Spring Cloud Stream 是一个构建消息驱动微服务的框架。应用程序通过 inputs 或者 outputs 来与 Spring Cloud Stream 中binder 交互,通过我们配置来 binding ,而 Spring Cloud Stream 的 binder 负责与消息中间件交互。所以,我们只需要搞清楚如何与 Spring Cloud Stream 交互就可以方便使用消息驱动的方式。

通过使用Spring Integration来连接消息代理中间件以实现消息事件驱动。Spring Cloud Stream 为一些供应商的消息中间件产品提供了个性化的自动化配置实现,引用了发布-订阅、消费组、分区的三个核心概念。目前仅支持RabbitMQ、Kafka。

为什么要用Srpring Cloud Stream
上面的项目已经实现了通过广播的方式实现一个post更新所有的客户端的配置更新功能,但是有一种情况下,假设一个项目里面用很多个微服务,里面用到的消息中间件既有mq,又有kafka,一个项目中有多个消息中间件,对于程序员,因为人员都不友好,这个时候就需要用到Spring Cloud Stream,它就类似jpa,屏蔽底层消息中间件的差异,程序员主要操作Spring Cloud Stream即可,而不需要管底层是kafka还是rabbitMq。

官方架构图

springcloud应用启动不打印logback日志 springcloud日志配置_Config_33


常用注解和api

组成

说明

Middleware

中间件,目前只支持RabbitMQ和Kafka

Binder

Binder是应用与消息中间件之间的封装,目前实行了Kafka和RabbitMQ的Binder,通过Binder可以很方便的连接中间件,可以动态的改变消息类型(对应于Kafka的topic,RabbitMQ的exchange),这些都可以通过配置文件来实现

@Input

注解标识输入通道,通过该输入通道接收到的消息进入应用程序

@Output

注解标识输出通道,发布的消息将通过该通道离开应用程序

@StreamListener

监听队列,用于消费者的队列的消息接收

@EnableBinding

指信道channel和exchange绑定在一起

Spring Cloud Stream的业务流程

springcloud应用启动不打印logback日志 springcloud日志配置_Config_34

下面开始实战

(1)生产者

创建生产者cloud-stream-rabbitmq-provider8801,引入pom,这里只是使用Stream,所以不引入Eureka和Actutor

<dependencies>
        <!--web启动器-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <!--stream rabbit -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-stream-rabbit</artifactId>
        </dependency>

        <!--单元测试-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

配置yml

springcloud应用启动不打印logback日志 springcloud日志配置_spring_35


代码

server:
  port: 8801
spring:
  application:
    name: cloud-stream-rabbitmq-provider8801

  cloud:
      stream:
        binders: #在此处配置要绑定的rabbitmq的服务信息
          defaultRabbit: # 表示定义的名称。用于binding整合
            type: rabbit #消息组件类型
            environment: #设置rabbitmq的相关环境配置
              spring:
                rabbitmq:
                  host: 39.96.22.34
                  port: 5675
                  username: guest
                  password: guest
        bindings: #服务的整合过程
          output: #这个名字是一个通道的名称
            destination: studyExchange  #表示要使用的Exchange名称定义
            content-type: application/json #设置消息类型,
        binder: defaultRabbit #设置要绑定的消息服务的具体设置

主启动类

springcloud应用启动不打印logback日志 springcloud日志配置_Stream_36


服务层创建生产者

接口

public interface IMessageProvider {
    public String send();
}

对应实现类

@EnableBinding(Source.class)
public class IMessageProviderImpl implements IMessageProvider {

    @Resource
    private MessageChannel output;

    @Override
    public String send() {
        String serial = UUID.randomUUID().toString();
        output.send(MessageBuilder.withPayload(serial).build());
        System.out.println("**********************serial = " + serial);
        return null;
    }
}

controller接口

@RestController
public class SendMessageController {
    @Resource
    private IMessageProvider messageProvider;

    @GetMapping("/sendMessage")
    public String sendMessage(){
        return messageProvider.send();
    }

}

生产者创建成功

(2)消费者

创建消费者模块1cloud-stream-rabbitmq-consumer8802,引入pom文件

<dependencies>
        <!--web启动器-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!--stream rabbit -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-stream-rabbit</artifactId>
        </dependency>

        <!--单元测试-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

跟生产者几乎一样的pom,配置yml

server:
  port: 8802
spring:
  application:
    name: cloud-stream-rabbitmq-consumer8802

  cloud:
    stream:
      binders: #在此处配置要绑定的rabbitmq的服务信息
        defaultRabbit: # 表示定义的名称。用于binding整合
          type: rabbit #消息组件类型
          environment: #设置rabbitmq的相关环境配置
            spring:
              rabbitmq:
                host: 39.96.22.34
                port: 5675
                username: guest
                password: guest
      bindings: #服务的整合过程
        input: #这个名字是一个通道的名称2
          destination: studyExchange #表示要使用的Exchange名称定义,指定使用哪个Exchange
          content-type: application/json #设置消息类型,
          binder: defaultRabbit #设置要绑定的消息服务的具体设置
          group: zsc8802  #分组

主启动类

springcloud应用启动不打印logback日志 springcloud日志配置_spring_37


服务层创建消费者

springcloud应用启动不打印logback日志 springcloud日志配置_Stream_38


代码

@Component
@EnableBinding(Sink.class)
public class ReceiveMessageListener {
    @Value("${server.port}")
    private String port;

    @StreamListener(Sink.INPUT)
    public void input(Message<String> message){
        System.out.println("消费者1号,---->接收到的消息:" + message.getPayload()+"\t port:"+port);
    }
}

创建完再创建一个消费者模块2cloud-stream-rabbitmq-consumer8803,步骤和配置跟上面一样,创建完启动这个3个项目

springcloud应用启动不打印logback日志 springcloud日志配置_Stream_39


查看rabbitmq

springcloud应用启动不打印logback日志 springcloud日志配置_spring_40


点进对应的交换机,发现里面有俩个用户,一个属于zsc8802分组,一个属于zsc8803分组

springcloud应用启动不打印logback日志 springcloud日志配置_Bus_41


此时发送8801生产者发送两条消息,两个消费者均消费了两条消息

springcloud应用启动不打印logback日志 springcloud日志配置_Config_42


如果将8802和8803项目分组分成同一个组,那么两条消息,会采用轮询的方式一人消费一条

springcloud应用启动不打印logback日志 springcloud日志配置_Bus_43


重启项目,生成者再发送两条消息,则会一人一条

springcloud应用启动不打印logback日志 springcloud日志配置_spring_44