SpringCloud总结2(Gateway、配置中心、服务总线)

8.Spring Cloud Gateway网关

8.1简介

 8.2案例

需求:将包含有 /user 的请求 路由到 http://127.0.0.1:9091/user/{id}

新建子项目gateway

pom.xml添加依赖

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

设置启动类

 编写配置文件

server:
  port: 10010
spring:
  application:
    name: api-gateway
  cloud:
    gateway:
      routes:
        # 路由id,可以随意写
        - id: user-service-route
          # 代理的服务地址
          uri: http://127.0.0.1:9091
          # 路由断言,可以配置映射路径
          predicates:   #http://127.0.0.1:10010/user/1  ->  http://127.0.0.1:9091/user/1
            - Path=/user/**
eureka:
  client:
    service-url:
      defaultZone: HTTP://127.0.0.1:10086/eureka
  instance:
    prefer-ip-address: true

 测试:http://localhost:10010/user/1

8.3面向服务的路由

上面的方式把路径写死了,这样是不对的。如果同一服务有多个实例的话,这样做显然不合理。 应该根据服务的名称,去Eureka注册中心查找 服务对应的所有实例列表,然后进行动态路由。

修改配置文件:

gateway将使用LoadBalancerClient把user-service通过eureka解析为实际的主机和端口,并进行ribbon负载均衡

8.4路由前缀

当微服务的地址与客户端的地址不一致时,可以配置路径过滤器对路径的前缀进行增加或删除

比如:

提供服务的地址:http://127.0.0.1:9091/user/1

添加前缀路径/user :访问http://127.0.0.1:10010/1就可以得到同样的效果

去除前缀路径/api:访问http://127.0.0.1:10010/api/user/1也可以得到同样的效果

修改配置文件

添加前缀

 去除前缀

8.5路由过滤器

8.5.1简介

Gateway网关一个重要的功能就是请求的鉴权,这个功能往往需要网关提供的过滤器来实现,上面路由前缀的处理就是使用过滤器来实现的。

常见的过滤器有:

 过滤器使用的时候是有规律的,比如之前使用的“StripPrefix”就是来自“StripPrefixGatewayFilterFactory”,直接把后面的“GatewayFilterFactory”来使用

过滤器的生命周期

Gateway Filter 的生命周期也类似 Spring MVC 的拦截器有两个: “pre” “post” “pre” “post”分别会在请求被执行前调用和被执行后调用

 这里的 pre post 可以通过过滤器的 GatewayFilterChain 执行fifilter方法前后来实现

使用场景

  • 请求鉴权:GatewayFilterChain 执行fifilter方法前,如果发现没有访问权限,直接就返回空。
  • 异常处理:GatewayFilterChain 执行fifilter方法后,记录异常并返回。
  • 服务调用时长统计: GatewayFilterChain 执行fifilter方法前后根据时间统计。

过滤器类型

  • 局部过滤器:通过 spring.cloud.gateway.routes.fifilters 配置在具体路由下,只作用在当前路由上;如果配置spring.cloud.gateway.default-fifilters 上会对所有路由生效也算是全局的过滤器;但是这些过滤器 的实现上都是要实现GatewayFilterFactory接口。
  • 全局过滤器:不需要在配置文件中配置,作用在所有的路由上;实现 GlobalFilter 接口即可。

8.5.2全局默认过滤器

 8.5.3自定义过滤器

1、自定义局部过滤器

我们通过一个需求来定义自己的过滤器

需求:

  • 在过滤器中将http://localhost:10010/api/user/1?name=vv中的参数name值获取到并输出到控制台
  • 并且参数名是可变的,也就是不一定每次都是name需要可以通过配置过滤器的时候做到配置参数名

创建MyParamGatewayFilterFactory.class

import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.stereotype.Component;

import java.util.Arrays;
import java.util.List;

@Component
public class MyParamGatewayFilterFactory extends AbstractGatewayFilterFactory<MyParamGatewayFilterFactory.Config> {

    static final String PARAM_NAME = "param";

    public MyParamGatewayFilterFactory() {
        super(Config.class);
    }

    @Override
    public List<String> shortcutFieldOrder() {
        return Arrays.asList(PARAM_NAME);
    }

    @Override
    public GatewayFilter apply(Config config) {
        return (exchange, chain) -> {
            // http://localhost:10010/api/user/1?name=vv config.param = name(yml中配置的name)
            //获取请求参数中param对应的参数名 的参数值
            ServerHttpRequest request = exchange.getRequest();
            if(request.getQueryParams().containsKey(config.param)) {
                request.getQueryParams().get(config.param)
                        .forEach(value ->  System.out.printf("------------局部过滤器--------%s = %s- -----", config.param, value));
            }
            return chain.filter(exchange);//执行请求
        };
    }

    //读取过滤器配置的参数
    public static class Config {
        //对应配置application.yml配置文件中过滤器参数
        private String param;

        public String getParam() {
            return param;
        }

        public void setParam(String param) {
            this.param = param;
        }
    }
}

修改配置文件:

 测试后:

2、自定义全局过滤器

需求:

编写全局过滤器,在过滤器中检查请求中是否携带token请求头。

  • 如果token请求头存在则放行;
  • 如果token为空或者不存在则设置返回的状态码为:未授权也不再执行下去。

 创建MyGlobalFilter.class

import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

@Component
public class MyGlobalFilter  implements GlobalFilter, Ordered {
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        System.out.println("--------------全局过滤器MyGlobalFilter------------------");
        String token = exchange.getRequest().getHeaders().getFirst("token");
        if(token==null || token.equals("")) {
            //设置响应状态码为未授权
            exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
            return exchange.getResponse().setComplete();
        }
        return chain.filter(exchange);
    }

    //实现Ordered,确定执行的顺序
    @Override
    public int getOrder() {
        //值越小越先执行
        return 1;
    }
}

测试:使用postman来模拟,因为浏览器请求无法设置token

正常访问浏览器时:

 当添加token时

8.6Gateway跨域设置

        在js 请求访问中,如果访问的地址与当前服务器的域名、 ip 或者端口号不一致则称为跨域请求。若不解决则不能获取到对应地址的返回结果。
如:从在 http://localhost:9090 中的 js 访问 http://localhost:9000 的数据,因为端口不同,所以也是跨域请求。
在访问Spring Cloud Gateway 网关服务器的时候,出现跨域问题的话,可以在网关服务器中通过配置解决,允许哪些服务是可以跨域请求的;具体配置如下:

 8.7 Gateway 和 Feign 区别

  • Gateway 作为整个应用的流量入口,接收所有的请求,如PC、移动端等,并且将不同的请求转发至不同的处理微服务模块,其作用可视为nginx;大部分情况下用作权限鉴定、服务端流量控制
  • Feign则是将当前微服务的部分服务接口暴露出来,并且主要用于各个微服务之间的服务调用

9.Spring Cloud Confifig分布式配置中心

        在分布式系统中,由于服务数量非常多,配置文件分散在不同的微服务项目中,管理不方便。为了方便配置文件集中管理,需要分布式配置中心组件。在Spring Cloud中,提供了 Spring Cloud Confifig ,它支持配置文件放在配置服务的本地,也支持放在远程Git 仓库

配置中心本质上也是一个微服务,同样需要注册到Eureka服务注册中心

9.1创建远程仓库

9.2创建配置文件

配置文件的命名方式 {application}-{profifile}.yml {application}-{profifile}.properties
  • application为应用名称
  • profifile用于区分开发环境,测试环境、生产环境等

 user-dev.yml,表示用户微服务开发环境下使用的配置文件。

我们这里将user-service工程的配置文件application.yml文件的内容复制作为user-dev.yml文件的内容

9.3搭建配置中心微服务

 添加依赖

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

 启动类上添加开启服务注解

 修改配置文件

server:
  port: 12000
spring:
  application:
    name: config-server
  cloud:
    config:
      server:
        git:
          #项目地址
          uri: https://gitee.com/vvupup/my-config1.git

eureka:
  client:
    service-url:
      defaultZone: http://127.0.0.1:10086/eureka

启动测试:http://localhost:12000/user-dev.yml

9.4获取配置中心配置

在user-service中添加依赖

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-config</artifactId>
</dependency>

删除application.yml

创建bootstrap.yml

spring:
  cloud:
    config:
      # 要与仓库中的配置文件的application保持一致
      name: user
      # 要与仓库中的配置文件的profile保持一致
      profile: dev
      # 要与仓库中的配置文件所属的版本(分支)一样
      label: master
      discovery:
        # 使用配置中心
        enabled: true
        # 配置中心服务名
        service-id: config-server

eureka:
  client:
    service-url:
      defaultZone: http://127.0.0.1:10086/eureka
bootstrap.yml 文件也是 Spring Boot 的默认配置文件,而且其加载的时间相比于 application.yml 更早。
application.yml bootstrap.yml 虽然都是 Spring Boot 的默认配置文件,但是定位却不相同。 bootstrap.yml可以理解成系统级别的一些参数配置,这些参数一般是不会变动的。application.yml 可以用来定义应用级别的参数,如果搭配 spring cloud confifig 使用, application.yml 里面定义的文件可以实现动态替换。
总结就是:
  • bootstrap.yml文件相当于项目启动时的引导文件,内容相对固定
  • application.yml文件是微服务的一些常规配置参数,变化比较频繁

 测试:http://localhost:9091/user/1(要先启动配置中心再启动user-service)

10.Spring Cloud Bus服务总线

引入问题:

如果我们更新Git仓库中的配置文件,那用户微服务是否可以及时接收到新的配置信息并更新呢

首先新增一个数据,在配置中心运行期间修改该值,看能否得到修改后的值。

经过测试后发现,配置中心能够动态的获取值,但是user-service只有重新启动后才能拿到修改后的值

如果有很多个用户微服务节点,那就要重新很多次才能都拿到更新后的值,这样就很麻烦。

10.1Spring Cloud Bus简介

        Spring Cloud Bus是用轻量的消息代理将分布式的节点连接起来,可以用于广播配置文件的更改或者服务的监控管理。也就是消息总线可以为微服务做监控,也可以实现应用程序之间相互通信。 Spring Cloud Bus 可选的消息代理有RabbitMQ Kafka。
需要注意的是 Spring Cloud Bus 底层是基于 RabbitMQ 实现的,默认使用本地的消息队列服务,所以需要提前启动本地RabbitMQ 服务

在消息队列中添加了“配置改变”的消息,当各个服务监听到消息改变时,就会刷新本地配置缓存 ,重新从配置中心获取配置

10.2 改变配置中心

在config-server中进行修改

添加依赖

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-bus</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-stream-binder-rabbit</artifactId>
</dependency>

修改配置文件

 

10.3 修改用户服务

user-service中添加依赖

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-bus</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-stream-binder-rabbit</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId> 
    <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>

修改user-service中的bootstrap.yml

修改user-service 项目的UserController 

修改git上面配置文件数据库连接的后缀,不然测试的时候可能会报错
url: jdbc:mysql://localhost:3306/hande?serverTimezone=GMT%2B8&useSSL=false

 10.4 测试

  1. 依次启动注册中心 eureka-server 、配置中心 confifig-server 、用户服务 user-service
  2. 访问用户微服务http://localhost:9091/user/1;查看IDEA控制台输出结果
  3. 修改Git仓库中配置文件 user-dev.yml test.name 内容
  4. 使用Postman或者RESTClient工具发送POST方式请求访问地址http://127.0.0.1:12000/actuator/bus-refresh
  5. 第五步:访问用户微服务系统控制台查看输出结果

10.5 说明

请求地址 http://127.0.0.1:12000/actuator/bus-refresh /actuator 是固定的 /bus-refresh是配置中心暴露的服务
请求http://127.0.0.1:12000/actuator/bus-refresh地址的作用是访问配置中心的消息总线服务,消息总线服务接收到请求后会向消息队列中发送消息,各个微服务会监听消息队列。当微服务接收到队列中的消息后,会重新从配置中心获取最新的配置信息

总体架构图

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值