消息总线组件 Spring Cloud Bus

单个工程更新

有了配置中心,我们就可以吧配置文件放到git上来统一管理了,但是如果配置文件发生了变化,客户端 又如何更新呢?

1.在配置文件中增加自定义属性

person:  id: 1  name: 李四

2.在customer-provider工程中的 Controller 中增加@Value注解引用属性

@RestController
public class MyController {@Value("${person.name}")private String name;@RequestMapping("getName")public String getName(){return name;}
}

3.访问url测试

更新配置文件配置文件

person:  id: 1  name: 张三

重新访问:

发现是没有变化的,也就是说配置文件更新后,如果想读取到最新的内容还是需要重启工程的。这 样就造成了很多不便。那么怎么才能不重启更新呢?

spring boot actuator执行器刷新操作

简单介绍一下spring boot actuator,是spring boot项目运行的一个监视器服务,启动项目的 endpoints就是由spring boot actuator输出的,包含了对spring boot的bean的监视,健康状况的管 理,可以通过/actuator 查看各种项目运行的信息。

1.在customer-provider 工程的pom文件加入spring boot actuator的引用

     <!--  spring boot actuator的引用--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-actuator</artifactId></dependency>

2.修改 bootstrap.yml 配置文件,增加如下内容:

#执行器刷新操作
management:endpoints:web:exposure:include: "*"

3.在Controller上增加 @RefreshScope 注解

@RestController
@RefreshScope
public class MyController {@Value("${person.name}")private String name;@RequestMapping("getName")public String getName(){return name;}
}

4.重新启动 customer-provider 工程

5.修改配置文件后访问下面url 执行刷新操作,使用post方法执行。

//查看actuator可以执行的方法(get形式访问)
http://localhost:9001/actuator
//执行刷新操作
http://localhost:9001/actuator/refresh

返回变更信息,就刷新成功了:

重新访问即可获取新的信息。

这样就实现了动态刷新,但是存在一个问题。每次更新文件都需要子服务手动刷新来获取最新值,服务量一旦过大对于维护以及体验都很糟糕。所以接下来介绍与spring cloud bus搭配实现无需子服务手动 刷新即可动态获取服务端最新值。

Spring cloud bus介绍

Spring cloud bus通过轻量消息代理连接各个分布的节点。这会用在广播状态的变化(例如配置变化) 或者其他的消息指令。Spring bus的一个核心思想是通过分布式的启动器对spring boot应用进行扩展, 也可以用来建立一个多个应用之间的通信频道。目前唯一实现的方式是用AMQP消息代理作为通道,同样特性的设置(有些取决于通道的设置)在更多通道的文档中。

Spring cloud bus被国内很多都翻译为消息总线,也挺形象的。大家可以将它理解为管理和传播所有分布式项目中的消息既可,其实本质是利用了MQ的广播机制在分布式的系统中传播消息,目前常用的有 Kafka和RabbitMQ。利用bus的机制可以做很多的事情,其中配置中心客户端刷新就是典型的应用场景之一,我们用一张图来描述bus在配置中心使用的机制:

根据此图我们可以看出利用Spring Cloud Bus做配置更新的步骤:

  • 提交代码触发post给客户端A发送bus/refresh

  • 客户端A接收到请求从Server端更新配置并且发送给Spring Cloud Bus

  • Spring Cloud bus接到消息并通知给其它客户端

  • 其它客户端接收到通知,请求Server端获取最新配置

  • 全部客户端均获取到最新的配置

RabbitMQ

由于Spring cloud bus服务需要MQ中间件,所以我们需要先安装RabbitMQ。rabbitMQ是一个在 AMQP协议标准基础上完整的,可服用的企业消息系统。它遵循Mozilla Public License开源协议,采用 Erlang 实现的工业级的消息队列(MQ)服务器,Rabbit MQ 是建立在Erlang OTP平台上。

  1. 安装Erlang

    下载地址:网盘链接
    提取码:dj1l
    本文选择erlang 22.0 Windows 64-bit,安装时可以改安装路径,其他直接默认安装就可以

    注意

    • erlang不支持中文,所以主机名一定要改成英文,以及C:/Users/用户名 也要改
    • 注意erlang与rabbitmq的版本问题:详情

设置环境变量,新建 ERLANG_HOME

此电脑–>鼠标右键“属性”–>高级系统设置–>环境变量–>“新建”系统环境变量

修改环境变量path,增加Erlang变量 %ERLANG_HOME%\bin 至path ;

在控制台输入erl ,出现版本信息,就成功了。

  1. 安装rabbitmq

链接:网盘链接
提取码:fwvv

安装时设置以下安装目录即可,一路下一步安装完毕。然后到rabbitmq安装目录下的sbin目录 下执行如下命令来安装管理插件:

.\rabbitmq-plugins.bat enable rabbitmq_management

如果出现下面情况:

解决方法

C:\Users\Administrator.erlang.cookie 同步至C:\Windows\System32\config\systemprofile.erlang.cookie

同时删除:C:\Users\Administrator\AppData\Roaming\RabbitMQ目录

成功后时展现下面信息:

3.为了方便以后使用,可以添加RabbitMQ到系统环境变量:

//添加环境变量
名字:RABBIT_HOME  值:你的安装位置,我的是 D:\RabbitMQ\rabbitmq_server-3.8.3
在path添加 %RABBIT_HOME%\sbin;

4.重启服务

rabbitmq-server

4.访问rabbitmq的管理界面

http://127.0.0.1:15672/用户名:guest
密码:guest

至此RabbitMQ安装完毕。

登录rabbitmq后创建新的用户并设置权限,以便客户端访问。

客户端改造

除去配置中心以外的所有服务包括 customer-consumercustomer-provider都是配置中心的客 户端,我们可以在每个工程中都增加如下内容:

pom文件

     <!--  消息总线起步依赖      --><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-bus-amqp</artifactId></dependency><!--  spring boot actuator的引用--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-actuator</artifactId></dependency>

bootstrap.yml中增加如下内容:

#消息组件
spring:rabbitmq:#指定host,运行在本地可以不写host: localhost#默认服务端口port: 5672username: lbbpassword: 123456
#执行器刷新操作
management:endpoints:web:exposure:include: "*"

重启工程

修改git服务器上的配置文件,访问接口:

//bus刷新接口 post方式提交
http://localhost:9001/actuator/bus-refresh

更新配置文件后在任意客户端访问 /actuator/bus-refresh 可以刷新所有客户端配置。

改进版本

在上面的流程中,我们已经到达了利用消息总线触发一个客户端 bus/refresh ,而刷新所有客户端的配 置的目的。但这种方式并不优雅。原因如下:

  • 打破了微服务的职责单一性。
  • 微服务本身是业务模块,它本不应该承担配置刷新的职责。
  • 破坏了微服务各节点的对等性。
  • 有一定的局限性。例如,微服务在迁移时,它的网络地址常常会发生变化,此时如果想要做到自动 刷新,那就不得不修改WebHook的配置。

因此我们将上面的架构模式稍微改变一下。

这时Spring Cloud Bus做配置更新步骤如下:

1、提交代码触发post请求给bus/refresh

2、server端接收到请求并发送给Spring Cloud Bus

3、Spring Cloud bus接到消息并通知给其它客户端

4、其它客户端接收到通知,请求Server端获取最新配置

5、全部客户端均获取到最新的配置

升级改造:

配置中心工程的pom文件中增加如下内容:

     <!--  消息总线起步依赖      --><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-bus-amqp</artifactId></dependency><!--  spring boot actuator的引用--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-actuator</artifactId></dependency>

配置中心的application.yml中增加如下内容:

#消息组件
spring:rabbitmq:#指定host,运行在本地可以不写host: localhost#默认服务端口port: 5672username: lbbpassword: 123456
#执行器刷新操作
management:endpoints:web:exposure:include: "*"

客户端工程中可以去掉对spring-boot-starter-actuator的依赖,及相关刷新配置。

重启config-centercustomer-providercustomer-consumer工程,此时若过配置发生改变,只需在配置中心刷新,而其他的客户端没有此功能,这样就把职责划分开了。

//注册中心对应端口下访问 ,执行刷新
http://localhost:9911/actuator/bus-refresh

微服务网关Zuul

微服务网关介绍

前面我们介绍了,Eureka用于服务的注册于发现,Feign支持服务的调用以及均衡负载,Hystrix处理服 务的熔断防止故障扩散,Spring Cloud Config服务集群配置中心,似乎一个微服务框架已经完成了。

我们还是少考虑了一个问题,外部的应用如何来访问内部各种各样的微服务呢?在微服务架构中,后端 服务往往不直接开放给调用端,而是通过一个API网关根据请求的url,路由到相应的服务。当添加API网 关后,在第三方调用端和服务提供方之间就创建了一面墙,这面墙直接与调用方通信进行权限控制,后 将请求均衡分发给后台服务端。

在微服务架构模式下后端服务的实例数一般是动态的,对于客户端而言很难发现动态改变的服务实例的 访问地址信息。因此在基于微服务的项目中为了简化前端的调用逻辑,通常会引入API Gateway作为轻 量级网关,同时API Gateway中也会实现相关的认证逻辑从而简化内部服务之间相互调用的复杂度。

Spring Cloud Zuul

在Spring Cloud体系中, Spring Cloud Zuul就是提供负载均衡、反向代理、权限认证的一个API gateway。pring Cloud Zuul路由是微服务架构的不可或缺的一部分,提供动态路由,监控,弹性,安 全等的边缘服务。Zuul是Netflix出品的一个基于JVM路由和服务端的负载均衡器。

简单使用

  1. 创建一个新的maven模块 gate-way ,pom文件中添加依赖:
        <!--    网关依赖    -->        <dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-zuul</artifactId></dependency>
  1. 创建application.yml配置文件
spring:application:name: gate-way
server:port: 8888
#配置路由信息
zuul:routes:baidu:path: /bing/**url: https://cn.bing.com/
  1. 编写启动类
@SpringBootApplication
@EnableZuulProxy //开启网关代理,启动类添加 @EnableZuulProxy ,支持网关路由。
public class GateWayRunner {public static void main(String[] args) {SpringApplication.run(GateWayRunner.class,args);}
}
  1. 启动工程并测试,访问:http://localhost:8888/bing/search?q=121

  2. 配置路由信息增加本地微服务映射:

spring:application:name: gate-way
server:port: 8888
#配置路由信息
zuul:routes:baidu:path: /bing/**url: https://cn.bing.com/customer:path: /provider/**url: http://localhost:9001/

服务化

通过url映射的方式来实现zull的转发有局限性,比如每增加一个服务就需要配置一条内容,另外后端的 服务如果是动态来提供,就不能采用这种方案来配置了。实际上在实现微服务架构时,服务名与服务实 例地址的关系在eureka server中已经存在了,所以只需要将Zuul注册到eureka server上去发现其他服 务,就可以实现对serviceId的映射。我们还是对 gate-way 进行改造。

  1. 添加依赖,对eureka的支持。
     <!--   eureka起步依赖     --><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-eureka-client</artifactId></dependency>
  1. 修改配置文件

application.yml中增加Eureka的配置信息。将路由的url改为 serviceId

spring:application:name: gate-way
server:port: 8888
#配置路由信息
zuul:routes:baidu:path: /bing/**url: https://cn.bing.com/customer:path: /provider/**#url: http://localhost:9001/serviceId: CUSTOMER-SERVICE#eureka
eureka:client:service-url:defaultZone: http://localhost:8000/eureka
  1. 测试 访问:http://localhost:8888/provider/getName ,如果成功输出,说明通过zuul成功调用了customer-client服务,如果要是多个服务集群的话还可以实现负载均衡 。

默认路由规则

但是如果后端服务多达十几个的时候,每一个都这样配置也挺麻烦的,spring cloud zuul已经帮我们做 了默认配置。默认情况下,Zuul会代理所有注册到Eureka Server的微服务,并且Zuul的路由规则如下: http://ZUUL_HOST:ZUUL_PORT/微服务在Eureka上的serviceId/** 会被转发到serviceId对应的微服务。

访问url:

//注意url中的server-id应该是小写字母。
http://localhost:8888/customer-service/getName

过滤器

其实Zuul还有更多的应用场景,比如:鉴权、流量转发、请求统计等等,这些功能都可以使用Zuul来实 现。Filter是Zuul的核心,用来实现对外服务的控制。Filter的生命周期有4个,分别是 “PRE”、 “ROUTING”、“POST”、“ERROR”,整个生命周期可以用下图来表示。

Zuul大部分功能都是通过过滤器来实现的,这些过滤器类型对应于请求的典型生命周期。

  • PRE: 这种过滤器在请求被路由之前调用。我们可利用这种过滤器实现身份验证、在集群中选择 请求的微服务、记录调试信息等。
  • ROUTING:这种过滤器将请求路由到微服务。这种过滤器用于构建发送给微服务的请求,并使用 Apache HttpClient或Netfilx Ribbon请求微服务。
  • POST:这种过滤器在路由到微服务以后执行。这种过滤器可用来为响应添加标准的HTTP Header、收集统计信息和指标、将响应从微服务发送给客户端等。
  • ERROR:在其他阶段发生错误时执行该过滤器。 除了默认的过滤器类型,Zuul还允许我们创建自 定义的过滤器类型。例如,我们可以定制一种STATIC类型的过滤器,直接在Zuul中生成响应,而 不将请求转发到后端的微服务。

6.1 自定义Filter

实现自定义Filter,需要继承ZuulFilter的类,并覆盖其中的4个方法。

public class TokenFilter extends ZuulFilter {//定义filter的类型,有pre、route、post、error四种@Overridepublic String filterType() {return "pre"; }//定义filter的顺序,数字越小表示顺序越高,越先执行@Overridepublic int filterOrder() {return 10; }//表示是否需要执行该filter,true表示执行,false表示不执行 @Overridepublic boolean shouldFilter() {return true; }//filter需要执行的具体操作 @Overridepublic Object run() throws ZuulException {return null; }
}

6.2 自定义Filter示例

我们假设有这样一个场景,因为服务网关应对的是外部的所有请求,为了避免产生安全隐患,我们需要 对请求做一定的限制,比如请求中含有Token便让请求继续往下走,如果请求不带Token就直接返回并 给出提示。

首先自定义一个Filter,在run()方法中验证参数是否含有Token。

public class TokenFilter extends ZuulFilter {@Overridepublic String filterType() {return "pre"; //定义filter的类型,有pre、route、post、error四种}@Overridepublic int filterOrder() {return 0; //定义filter的顺序,数字越小表示顺序越高,越先执行}@Overridepublic boolean shouldFilter() {return true; //表示是否需要执行该filter,true表示执行,false表示不执行}@Overridepublic Object run() throws ZuulException {//获取request看是否含token//请求上下文RequestContext ctx = RequestContext.getCurrentContext();//获取请求对象HttpServletRequest request = ctx.getRequest();// 获取请求的参数String token = request.getParameter("token");//token无效if (token == null || token.length() < 1){//不对其进行路由转发ctx.setSendZuulResponse(false);//状态码ctx.setResponseStatusCode(400);//返回错误信息ctx.setResponseBody("token is empty");ctx.set("isSuccess", false);return null;}else {//token有效//不对其进行路由转发ctx.setSendZuulResponse(true);//状态码ctx.setResponseStatusCode(200);ctx.set("isSuccess", true);return null;}}
}

TokenFilter加入到请求拦截队列,修改启动类:

@SpringBootApplication
@EnableZuulProxy //开启网关代理
public class GateWayRunner {public static void main(String[] args) {SpringApplication.run(GateWayRunner.class,args);}@Beanpublic TokenFilter getTokenFilter(){return new TokenFilter();}
}

这样就将我们自定义好的Filter加入到了请求拦截中。

测试

访问地址: http://localhost:8888/customer-service/getName ,返回:token is empty ,请求被拦截返回。

访问地址: http://localhost:8888/customer-service/getName?token=xx ,返回:json数据,说明请求正常响应。

通过上面这例子我们可以看出,我们可以使用“PRE”类型的Filter做很多的验证工作,在实际使用中我们 可以结合shiro、oauth2.0等技术去做鉴权、验证。

SpringCloud之消息总线组件及微服务网关相关推荐

  1. 微服务网关和服务注册中心

    在前面谈微服务架构的时候,已经有多篇文章都谈到过微服务网关,由于微服务网关本身也是提供代理,路由,安全,日志,负载均衡,流量控制等能力,因此我谈的最多的就是可以将微服务网关理解为轻量的ESB服务总线, ...

  2. 【springcloud合集】02:微服务架构理论基础

    一个毕业后差一点进大厂的程序员的进阶之路--既为巩固知识,也为增长粉丝. 个人微信公众号[一条IT],每天分享软件,资源,教程,福利. 基于分布式的微服务架构满足哪些维度? 服务注册与发现 服务调用 ...

  3. SpringCloud 微服务网关Gateway介绍及简单路由配置

    概述:什么是微服务网关?为了解决用户客户端在调用微服务系统中的多个消费者工程接口时,需要维护非常多的消费者应用接口地址等信息,以及可能存在不同应用见的调用跨域等问题,微服务网关组件随即出现.网关作为用 ...

  4. 利用SpringCloud搭建一个最简单的微服务框架

    利用SpringCloud搭建一个最简单的微服务框架 https://blog.csdn.net/caicongyang/article/details/52974406 1.微服务 微服务主要包含服 ...

  5. SpringCloud Gateway微服务网关实战与源码分析-上

    概述 定义 Spring Cloud Gateway 官网地址 https://spring.io/projects/spring-cloud-gateway/ 最新版本3.1.3 Spring Cl ...

  6. SpringCloud 微服务网关Gateway 动态路由配置

    概述:在上一章节<SpringCloud 微服务网关Gateway介绍及简单路由配置>中我们讲述了Gateway的最简单的路由配置方式.但是其中比较明显的问题就是我们在配置路由服务的地址时 ...

  7. SpringCloud 使用Zuul构建微服务网关

    什么是网关? 之前,我一直觉得对这个概念理解的不够清晰,使用了微服务后,大概总结了一下,通俗来讲可以理解如下,某个应用平台一旦需要为外界提供开放接口服务,平台为了对开发的接口做统一管理,权限认证,路由 ...

  8. Jenkins+GitLab+Docker+SpringCloud+Kubernetes实现可持续自动化微服务

    Jenkins+GitLab+Docker+SpringCloud+Kubernetes实现可持续自动化微服务

  9. 微服务网关:SpringCloud Gateway保姆级入门教程

    什么是微服务网关 SpringCloud Gateway是Spring全家桶中一个比较新的项目,Spring社区是这么介绍它的: 该项目借助Spring WebFlux的能力,打造了一个API网关.旨 ...

最新文章

  1. MIT开发新加密货币,用户所需数据比比特币减少99%
  2. HDU 2660 Accepted Necklace
  3. 安装eclipse中html/jsp/xml editor插件以及改动html页面的字体
  4. ATI显卡开启fedora9的3d后果的一些条记
  5. Openstack概论
  6. SpringBoot之第一个Restfu示例
  7. 【转】程序员的十种级别
  8. Visual Studio 2013 + Intel(R) Visual Fortran 安装教程
  9. MODIS数据之HEG拼接重采样批处理(Python_MacOS)
  10. sysbench 压力测试工具(实战)
  11. Linux通过df命令查看显示磁盘空间满,但实际未占用问题
  12. 期刊缩写合辑【JCR+ISO】
  13. ubuntu20.04搭建janus服务器
  14. Python进阶(五)浅谈python匿名函数
  15. python 02 --python从安装到学习精品网站(廖雪峰官方网站)
  16. android充当server服务器
  17. leetcode 大礼包
  18. Android OTA版本任意升级
  19. 聚划算99划算节,再次验证下沉市场大变局
  20. Windows 7系统中被忽略的七个实用功能

热门文章

  1. 程序员兼职怎样报价力求中标?——接私活的项目报价策略
  2. 批量将txt文件转为excel文件
  3. 有容云:容器驱动的PaaS平台实现方案(上)
  4. 牛逼的python代码_牛逼啊!一个随时随地写Python代码的神器
  5. 群邑智库:2018年1-9月主要央卫视电视剧回顾
  6. 10分钟上手pythonpandas_10分钟学pandas(10 Minutes to pandas)-全文翻译
  7. IAR中eww、ewp、ewd···等各文件的含义和用途
  8. Vue使用photo-sphere-viewer360°×180°全景插件模拟VR看房、房间切换和自定义标注
  9. java解决行驶证识别问题
  10. 直播软件开发Android直播悬浮窗实现