基于SpringCloud的微服务架构学习笔记(4)http客户端Feign和网关GateWay

2. http客户端Feign

Feign是一种新的使用http进行远程调用的方式。

2.1 Feign替代RestTemplate

2.1.1 RestTmmplate方法调用存在的问题

1)使用方法:在启动类书写一个方法,然后通过url在service中进行调用

String url = "http://userservice/user/" + order.getUserId();
User user = restTemplate.getForObject(url, User.class);
  • 代码可读性太差,需要固定输入一个URL,不够灵活
  • 当参数变得复杂的时候,URL难以维护。

2.1.2. Feign的介绍

1)是一种申明式的http客户端,作用是帮助我们优雅实现http请求的发送,解决上面提到的问题。
2) 实现逻辑还是差不多的,都是为了生成一个url进行远程调用。只不过在Feign中,采用申明式结构进行URL的拆分再组装。

2.1.3. Feign的使用

  1. 在order-service的pom文件中引入依赖:spring-cloud-starter-openfeign
<dependency>
    <groupId>org.springframework.cloud</groupId>
     <artifactId>spring-cloud-starter-openfeign</artifactId> 
</dependency>
  1. 在orderservice的启动类中添加注解,开启Feign的功能:@EnableFeignClients
  1. 在Feign-api项目中编写Feign的客户端(Feign-client)
    为了相对应,需要和user中的controller中的类保持参数的一直性
@FeignClient("userservice")
public interface UserClient {
    
    
    @GetMapping("/user/{id}") 
    User findById(@PathVariable("id") Long id);
}

上述定义Feign客户端中,包含很多信息:
(1)服务名称:userservice
(2)请求方式:Get
(3)请求路径:/user/{id}
(4)请求参数:Long id
(5)返回对象:User

  1. 用Feign客户端代替RestTemplate

第二行红色,两行给为一行了!

        String url="http://localhost:8081/user/"+order.getUserId();  //获取用户的id信息
        User user=restTemplate.getForObject(url,User.class);   //通过url进行远程调用,并把得到的数据变为user格式
  1. 小结
    1)引入依赖
    2)启动类添加注解@EnableFeignClients
    3)编写FeignClient接口
    4)使用FeignClient中定义的方法替代RestTemplate

2.2 自定义配置

一般使用比较多的是:日志级别的修改,共有四种级别:NONE,BASIC,HEADERS,FULL,一般默认选用NONE即可

2.3 Feign使用优化

2.3.1 优化的底层原理

主要是在Feign底层进行优化,即采用具有连接池的原理。
Feign底层的客户端实现:
1)URLConnection:默认实现,不支持连接池(性能一般)
2)Apache HttpClient:支持连接池(不用每次都请求链接,效率更高)
3)OKHttp:支持连接池

2.3.2 优化的方向

优化的方向:
1)使用连接池代替默认的URLConnection
2)日志级别的修改:使用NONE和BASIC,更加简洁。

2.3.3 连接池配置

Feign添加HttpClient的支持,故需要引入依赖和配置连接池

  1. 在Feign-api中引入依赖
<!--feign-api的依赖 -->
<dependency>
     <groupId>cn.itcast.demo</groupId>
     <artifactId>feign-api</artifactId>
     <version>1.0</version>
</dependency>
  1. 配置连接池(同时修改日志级别)
feign:
  client:
  config:
    default: # default全局的配置
  	  loggerLevel: BASIC # 日志级别,BASIC就是基本的请求和响应信息 
  	  
  httpclient:    
  	 enabled: true # 开启feign对HttpClient的支持
  	 max-connections: 200 # 最大的连接数
  	 max-connections-per-route: 50 # 每个路径的最大连接数

2.4 最佳实践

2.4.1 方式一:继承

  1. 方式:从 2.1.3. Feign的使用中可知,Feign客户端的编写与user服务service的编写很像,故可以抽象出相同部分,然后给这两个地方继承。
  2. 缺点:1)两个服务会产生紧耦合,并且父接口参数列表中的映射并不会被继承。

2.4.2 方式二:抽取

  1. 方法:将FeignClient抽取为独立的模块,并把与接口与欧冠的POJO,默认的Feign配置都放到这个模块中来,提供给所有的消费者使用。(其他消费者只需要在启动类中添加注解@EnableFeignClients即可使用)
    注意事项:由于是新建的一个项目Feign-api,故其他服务在使用过程中需要引入依赖才能使用其他项目的服务
        <!--引入feign的统一api-->
        <dependency>
            <groupId>cn.itcast.demo</groupId>
            <artifactId>feign-api</artifactId>
            <version>1.0</version>
        </dependency>
  1. 抽取FeignClient的步骤
    1)创建mudule并依赖首先创建一个module,取名为feign-api,然后引入feign的starter依赖
    2)将order中编写的UserLcient,User,DefaultFeignConfiguration都复制到feign-api项目中
    3)在order-service引入feign-api的依赖
    4)修改order-service中的所有与上述三个组件有关的import部分,改成导入feign-api的包
    5)重启测试
  2. FeignClient不在启动类扫描包饭内内解决方法
    1)指定FeignClient所在包(范围大,全导进来了)
@EnableFeignClients(basePackages = "cn.itcast.feign.clients")

2)指定FeignClient字节码(小范围)

@EnableFeignClients(clients = {
    
    UserClient.class})

3. 统一网关Gateway

3.1 为什么需要网关

1. 网关的作用
1)身份认证和权限校验等:不是什么用户通过链接都能够访问的,需要指定的用户名等情况,或者需要某一些权限处于开启状态;
2)服务路由和负载均衡:将用户请求路由到微服务,并实现负载均衡。网关具有负载均衡的作用,故不需要自己去配置Ribbon

3)请求限流:同一个时刻,对于服务的访问,限制流量,不能够过于频繁访问。
2. 网关技术的实现
目前SpringCloud中,网关的实现包括两种:
1)gateway:SpringCloudGateWay则属于Spring5中提供的WebFlux,属于响应式编程的实现,具有更好的性能。
2)zuul:基于Servlet的实现,属于阻塞式的编程
3)区别:响应式编程和阻塞式编程。

3.2 GateWay的快速入门

  1. 建module,引依赖:网关依赖和服务发现依赖
<!--网关依赖-->
<dependency>
    <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<!--nacos服务发现依赖-->
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId> 
</dependency>
  1. 配置文件:编写路由配置和nacos的地址(编码形式设置网关)
    根据上面可知,网关路由route的配置包含以下四个部分:

1) 路由id:路由的id,是路由的唯一表示
2)路由目标(uri):路由的目标地址,http代表固定地址,lb代表根据服务名负载均衡
3)路由断言(predicates):判断路由的规则,例如Path=/user/**,判断路径是否以/user开头,如果是则符合
4)路由过滤器(filters):对请求和相应做处理

  1. 网关的执行过程

3.3 断言工厂

上述配置中的断言都是通过断言工厂进行执行的:读取用户定义的断言条件,对请求做出判断

1)我们在配置文件中书写的断言规则只是字符串,这些字符串会被Predicate Factory读取并处理,转变为路由判断的条件
2)例如Path=/user/**是按照路径匹配,规则是org.springframework.cloud.gateway.handler.predicate.PathRoutePredicateFactory类处理的
3)像这样的断言工厂还有好几十个,可自行通过说明进行使用。

3.4 过滤器工厂

1. 过滤器工厂介绍
在路由确定之后会通过过滤器进行过滤操作,再通过负载均衡分配到具体的服务中去。
过滤器可以对进入网关的请求微服务返回的响应做处理

2. 过滤器工厂种类
Spring提供了31种不同的路由过滤器工厂

3. 过滤器工厂使用案例
1)要求:给所有进入userservice的请求,添加一个请求头:Truth=itcast is freaking awesome!
2)实现步骤
(1)在gateway中修改配置文件,给userservice的路由添加过滤器

spring:
  cloud:
   gateway:
    routes: # 网关路由配置
      - id: user-service         #路由id
        uri: lb://userservice    #路由路径
        predicates:              #路由断言
          - Path=/user/**’      #判断是否存在/user路径
       	filters: # 过滤器,带有s,可以有多个操作   
          - AddRequestHeader=Truth, Itcast is freaking awesome!  # 添加请求头

(2)如果要对所有的路由都生效,故需要将过滤器工厂写到default下面,格式如下:

3.5 全局过滤器(GlobalFilter)

3.5.1 什么是全局过滤器,为什么需要全局过滤器

1)全局过滤器能够处理一切进入网关的请求和微服务相应,与GatewayFilter的作用是一致的。
2)与GatewayFilter的区别:GatewayFilter是通过配置文件实现的,处理逻辑固定;GlobalFilter的逻辑需要自己写代码实现,更加灵活!

3.5.2. 全局过滤器的实现方式

1)实现GlobalFilter接口:

全局过滤器 GlobalFilter
public interface GlobalFilter {
    
    
   /**
       *  处理当前请求,有必要的话通过{@link GatewayFilterChain}将请求交给下一个过滤器处理
    *
    * @param exchange 请求上下文,里面可以获取Request、Response等信息
    * @param chain 用来把请求委托给下一个过滤器 
    * @return {@code Mono<Void>} 返回标示当前过滤器业务结束
    */
     Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain);
}

2)添加@Order注解或者实现Ordered接口:为了给过滤器进行优先级排序
3)编写处理逻辑
4)添加注解@Component,注入bean中,方便使用

3.5.3. 全局过滤器的实现案例

  1. 问题说明:定义全局过滤器,拦截并判断用户身份
    需求:定义全局过滤器,拦截请求,判断请求的参数是否满足下面条件:

参数中是否有authorization,
authorization参数值是否为admin

  • 参数中是否有authorization,
  • authorization参数值是否为admin
  • 如果同时满足则放行,否则拦截
  1. 逻辑实现

五步走:
(1)获取请求参数
(2)获取authorization参数
(3)校验
(4)放行
(5)禁止访问/结果处理

3.5 过滤器的执行顺序

三种过滤器:当前路由过滤器,DefaultFilter过滤器,GlobalFilter
在这里插入图片描述

  1. 首先根据指定的order值进行比较:order值越小,优先级越高,执行顺序越靠前。
    1)GlobalFilter通过实现Odered接口,或者添加@Order注解指定order值,有我们自己指定
    2)路由过滤器和defaultfilter过滤器的order的值由Spring指定,默认是按照声明顺序从1开始递增
    3)在order值相同时,会按照:defaultFilter > 路由过滤器 > GlobalFilter 的顺序执行

3.6 限流过滤器

  1. 作用:限流是保护服务器,避免因为过多的请求而导致服务器过载或者宕机
  2. 限流算法:计算机算法,漏桶算法,令牌桶算法。

3.7 小总结

网关其实并不需要改变其他服务中的代码,只是一个额外的功能,单独在网关服务中,其实现的原理有:
1)首先生成一个网关服务,添加启动类
2)引入注册发现依赖,引入网关依赖
3)网关的过滤作用在配置文件中声明实现(路由过滤器和defaultfilter,都是申明式的)
4)通过GlobalFilter过滤器实现:通过添加一个类,继承GlobalFilter接口,再书写逻辑,可以更加灵活的操作。

在微服务体系中,配置文件和依赖非常重要

参考文献
1)黑马程序员SpringCloud+RabbitMQ+Docker+Redis+搜索+分布式,系统详解springcloud微服务技术栈课

图片:

红色字体

用于复制

猜你喜欢

转载自blog.csdn.net/qq_42974034/article/details/129486525