一、概念
1,简介
微服务意味着要将单体应用中的业务拆分为一个个子服务,每个服务的粒度相对较小,因此系统中会出现大量的服务。由于每个服务都需要必要的配置信息才能运行,所以一套集中式的、动态的配置管理设施是必不可少的。
2,作用
- 集中管理配置文件
- 不同环境不同配置,动态化的配置更新,分环境部署比如dev/test/prod/beta/release
- 运行期间动态调整配置,不再需要在每个服务部署的机器上编写配置文件,服务会向配置中心统一拉取配置自己的信息
- 当配置发生变动时,服务不需要重启即可感知配置的变化并应用新的配置(post、curl访问刷新)
二、案例
源码:cloud-config
1,配置SpringCloud Config Server
添加依赖:
<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
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客户端之动态刷新
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(); }
发送消息
@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; } }
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(); }
消息消费
@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); } }