小言_互联网的博客

分布式微服务3

402人阅读  评论(0)

目录

Feign远程调用

基于Feign远程调用

Feign替代RestTemplate

1.引入依赖

2.添加注释

 3.编写Feign的客户端

4.测试

 5.总结

自定义配置

1.引入依赖

2.配置连接池

3.总结

Gateway网关

Gateway快速入门

1.创建gateway服务,引入依赖

2.编写启动类

3.编写基础配置和路由规则

4.重启测试

过滤器

请求头过滤器

默认过滤器DefaultFilter

全局过滤器GlobalFilter

自定义全局过滤器

过滤器执行顺序

总结


Feign远程调用

基于Feign远程调用

RestTemplate方式调用存在的问题

先来看我们以前利用RestTemplate发起远程调用的代码:

存在下面的问题:

代码可读性差,编程体验不统一

参数复杂URL难以维护

Feign替代RestTemplate

1.引入依赖

我们在order-service服务的pom文件中引入feign的依赖


  
  1. <dependency>
  2. <groupId>org.springframework.cloud</groupId>
  3. <artifactId>spring-cloud-starter-openfeign</artifactId>
  4. </dependency>

2.添加注解

 

 3.编写Feign的客户端

在order-service中新建一个接口,内容如下


  
  1. package com.tledu.order.client;
  2. import com.tledu.order.pojo.User;
  3. import org.springframework.cloud.openfeign.FeignClient;
  4. import org.springframework.web.bind.annotation.GetMapping;
  5. import org.springframework.web.bind.annotation.PathVariable;
  6. @FeignClient("userservice")
  7. public interface UserClient {
  8. @GetMapping("/user/{id}")
  9. User findById (@PathVariable("id") Long id);
  10. }

4.测试

修改order-service中的OrderService类中的queryOrderById方法,使用Feign客户端代替RestTemplate:

 5.总结

使用Feign的步骤:

引入依赖

添加@EnableFeignClients注解

编写FeignClient接口

使用FeignClient中定义的方法代替RestTemplate

自定义配置

基于配置文件修改feign的日志级别可以针对单个服务:


  
  1. feign:
  2. client:
  3. config:
  4. userservice: # 针对某个微服务的配置
  5. loggerLevel: FULL # 日志级别

而日志的级别分为四种:

  • NONE:不记录任何日志信息,这是默认值。
  • BASIC:仅记录请求的方法,URL以及响应状态码和执行时间
  • HEADERS:在BASIC的基础上,额外记录了请求和响应的头信息
  • FULL:记录所有请求和响应的明细,包括头信息、请求体、元数据。

性能优化

Feign的性能优化

Feign底层发起http请求,依赖于其它的框架。其底层客户端实现包括:

URLConnection:默认实现,不支持连接池

Apache HttpClient :支持连接池

OKHttp:支持连接池

因此提高Feign的性能主要手段就是使用连接池代替默认的URLConnection。

这里我们用Apache的HttpClient来演示。

1.引入依赖

在order-service的pom文件中引入Apache的HttpClient依赖


  
  1. <!--httpClient的依赖 -->
  2. <dependency>
  3. <groupId>io.github.openfeign</groupId>
  4. <artifactId>feign-httpclient</artifactId>
  5. </dependency>

2.配置连接池

在order-service的application.yml中添加配置


  
  1. feign:
  2. client:
  3. config:
  4. default: # default全局的配置
  5. loggerLevel: BASIC # 日志级别,BASIC就是基本的请求和响应信息
  6. httpclient:
  7. enabled: true # 开启feign对HttpClient的支持
  8. max-connections: 200 # 最大的连接数
  9. max-connections-per-route: 50 # 每个路径的最大连接数

3.总结

Feign的优化:

1.日志级别尽量用basic

2.使用HttpClient或OKHttp代替URLConnection

引入feign-httpClient依赖

配置文件开启httpClient功能,设置连接池参数

Gateway网关

Gateway网关是我们服务的守门神,所有微服务的统一入口。

网关的核心功能特性

权限控制:网关作为微服务入口,需要校验用户是是否有请求资格,如果没有则进行拦截。

路由和负载均衡:一切请求都必须先经过gateway,但网关不处理业务,而是根据某种规则,把请求转发到某个微服务,这个过程叫做路由。当然路由的目标服务有多个时,还需要做负载均衡。

限流:当请求流量过高时,在网关中按照下流的微服务能够接受的速度来放行请求,避免服务压力过大。

Gateway快速入门

下面,我们就演示下网关的基本路由功能。基本步骤如下:

  1. 创建SpringBoot工程gateway,引入网关依赖
  2. 编写启动类
  3. 编写基础配置和路由规则
  4. 启动网关服务进行测试

1.创建gateway服务,引入依赖


  
  1. <!--网关-->
  2. <dependency>
  3. <groupId>org.springframework.cloud</groupId>
  4. <artifactId>spring-cloud-starter-gateway</artifactId>
  5. </dependency>
  6. <!--nacos服务发现依赖-->
  7. <dependency>
  8. <groupId>com.alibaba.cloud</groupId>
  9. <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
  10. </dependency>

2.编写启动类


  
  1. package cn.itcast.gateway;
  2. import org.springframework.boot.SpringApplication;
  3. import org.springframework.boot.autoconfigure.SpringBootApplication;
  4. @SpringBootApplication
  5. public class GatewayApplication {
  6. public static void main (String[] args) {
  7. SpringApplication.run(GatewayApplication.class, args);
  8. }
  9. }

3.编写基础配置和路由规则

创建application.yml文件,内容如下


  
  1. server:
  2. port: 10010 # 网关端口
  3. spring:
  4. application:
  5. name: gateway # 服务名称
  6. cloud:
  7. nacos:
  8. server-addr: localhost:8848 # nacos地址
  9. gateway:
  10. routes: # 网关路由配置
  11. - id: user-service # 路由id,自定义,只要唯一即可
  12. # uri: http://127.0.0.1:8081 # 路由的目标地址 http就是固定地址
  13. uri: lb://userservice # 路由的目标地址 lb就是负载均衡,后面跟服务名称
  14. predicates: # 路由断言,也就是判断请求是否符合路由规则的条件
  15. - Path=/user/** # 这个是按照路径匹配,只要以/user/开头就符合要求

4.重启测试

重启网关,访问http://localhost:10010/user/1时,符合/user/**规则,请求转发到uri:http://userservice/user/1,得到了结果:

 

过滤器

路由过滤器

请求头过滤器

下面我们以AddRequestHeader 为例来讲解。

需求:给所有进入userservice的请求添加一个请求头:Truth=itcast is freaking awesome!

只需要修改gateway服务的application.yml文件,添加路由过滤即可:


  
  1. spring:
  2. cloud:
  3. gateway:
  4. routes:
  5. - id: user-service
  6. uri: lb://userservice
  7. predicates:
  8. - Path=/user/**
  9. filters: # 过滤器
  10. - AddRequestHeader=Truth, tledu is freaking awesome! # 添加请求头

当前过滤器写在userservice路由下,因此仅仅对访问userservice的请求有效。

默认过滤器DefaultFilter

如果要对所有的路由都生效,则可以将过滤器工厂写到default下。格式如下


  
  1. spring:
  2. cloud:
  3. gateway:
  4. routes:
  5. - id: user-service
  6. uri: lb://userservice
  7. predicates:
  8. - Path=/user/**
  9. default-filters: # 默认过滤项
  10. - AddRequestHeader=Truth, tledu is freaking awesome!

检查请求头是否设置成功


  
  1. @GetMapping("{orderId}")
  2. public Order queryOrderByUserId (@PathVariable("orderId") Long orderId, HttpServletRequest request, @RequestHeader(value = "Truth") String va) {
  3. System.out.println(va);
  4. Enumeration<String> headerNames = request.getHeaderNames();
  5. while (headerNames.hasMoreElements()){
  6. String s = headerNames.nextElement();
  7. if( "Truth".equals(s)){
  8. String header = request.getHeader(s);
  9. System.out.println(header);
  10. }
  11. }
  12. // 根据id查询订单并返回
  13. return orderService.queryOrderById(orderId);
  14. }

全局过滤器GlobalFilter

全局过滤器的作用也是处理一切进入网关的请求和微服务响应,与GatewayFilter的作用一样。区别在于GatewayFilter通过配置定义,处理逻辑是固定的;而GlobalFilter的逻辑需要自己写代码实现。

定义方式是实现GlobalFilter接口。


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

自定义全局过滤器

需求:定义全局过滤器,拦截请求,判断请求的参数是否满足下面条件:

在gateway中定义一个过滤器:


  
  1. package cn.itcast.gateway.filters;
  2. import org.springframework.cloud.gateway.filter.GatewayFilterChain;
  3. import org.springframework.cloud.gateway.filter.GlobalFilter;
  4. import org.springframework.core.annotation.Order;
  5. import org.springframework.http.HttpStatus;
  6. import org.springframework.stereotype.Component;
  7. import org.springframework.web.server.ServerWebExchange;
  8. import reactor.core.publisher.Mono;
  9. @Order(-1)
  10. @Component
  11. public class AuthorizeFilter implements GlobalFilter {
  12. @Override
  13. public Mono<Void> filter (ServerWebExchange exchange, GatewayFilterChain chain) {
  14. // 1.获取请求参数
  15. MultiValueMap<String, String> params = exchange.getRequest().getQueryParams();
  16. // 2.获取authorization参数
  17. String auth = params.getFirst( "authorization");
  18. // 3.校验
  19. if ( "admin".equals(auth)) {
  20. // 放行
  21. return chain.filter(exchange);
  22. }
  23. // 4.拦截
  24. // 4.1.禁止访问,设置状态码
  25. exchange.getResponse().setStatusCode(HttpStatus.FORBIDDEN);
  26. // 4.2.结束处理
  27. return exchange.getResponse().setComplete();
  28. }
  29. }

过滤器执行顺序

请求进入网关会碰到三类过滤器:当前路由的过滤器、DefaultFilter、GlobalFilter

请求路由后,会将当前路由过滤器和DefaultFilter、GlobalFilter,合并到一个过滤器链(集合)中,排序后依次执行每个过滤器:

排序的规则是什么呢?

总结

过滤器的作用是什么?

对路由的请求或响应做加工处理,比如添加请求头

配置在路由下的过滤器只对当前路由的请求生效

defaultFilters的作用是什么?对所有路由都生效的过滤器


转载:https://blog.csdn.net/qq_43009048/article/details/128856528
查看评论
* 以上用户言论只代表其个人观点,不代表本网站的观点或立场