Java分布式微服务2——声明式Http客户端(Feign)与网关(Gateway)

文章目录

  • Http声明式客户端Feign
    • Feign介绍与使用
    • Feign自定义配置
    • Feign性能优化
    • Feign最佳实践方案
  • 网关Gateway
    • 网关Gateway的作用与搭建
    • 路由断言工厂Route Predicate Factory
    • 路由过滤器GatewayFilter
    • 全局过滤器
    • 过滤器执行顺序
    • 网关的跨域处理

Http声明式客户端Feign

Feign介绍与使用

RestTemplate方式进行远程调用存在的问题

  • 可读性差
  • 对复杂url不方便操作

Feign是一个声明式的Http客户端

  1. 它把远程调用的方式与Spring MVC的Controller相似化了
  2. 它接入了Ribbon自动实现负载均衡

使用步骤:

  1. 引入依赖
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
  1. 在启动类添加@EnableFeignClients开启Feign的自动装配功能,@Enable开头的注解什么意思
  2. 编写Feign客户端,创建一个接口加上@FeignClient,其利用了SpringMVC的映射注解声明远程调用的信息。

@GetMapping注解在Spring MVC中和Feign中都可以使用,用于定义Restful的接口,但它们的用途不同。在Spring MVC中,它用于将HTTP GET请求映射到指定的处理方法上;而在Feign中,它用于定义Feign客户端接口中的方法,用于向远程服务发送HTTP GET请求。

@FeignClient("userservice") // 指定要请求的服务名称
public interface UserClient {
    @GetMapping("/user/{id}") // GetMapping是标明请求方式,不仅仅是Controller中的监听Get请求,这里是发送请求的方式
    User findById(@PathVariable Long id);
}
  1. 使用客户端进行远程调用
@Resource
private UserClient userClient;

User user = userClient.findById(order.getUserId());

Feign自定义配置

Java分布式微服务2——声明式Http客户端(Feign)与网关(Gateway)_第1张图片
方式一:改配置文件

# Feign日志级别
feign:
  client:
    config:
      default:
        loggerLevel: HEADERS

方式二:在Configuration类中声明一个对应类型的Bean
Java分布式微服务2——声明式Http客户端(Feign)与网关(Gateway)_第2张图片

Feign性能优化

Feign的底层客户端实现有三种:

  • URLConnection: 默认实现,不支持连接池
  • Apache HttpClient: 支持连接池(这里是Http连接的连接池,与Druid数据库连接池不同)
  • OKHttp: 支持连接池

这样我们就可以切换客户端并配置连接池来改善性能
Feign的性能优化可以从下面2个方面入手:

  • 使用连接池
  • 日志级别设为basic或者none

替换客户端实现为HttpClient:

  1. 引入HttpClient依赖
<!--        feign的httpclient-->
        <dependency>
            <groupId>io.github.openfeign</groupId>
            <artifactId>feign-httpclient</artifactId>
        </dependency>
  1. 在配置文件中新增连接池配置
feign:
  client:
    config:
      default:
        loggerLevel: BASIC
  httpclient:
    enabled: false
    max-connections: 200
    max-connections-per-route: 50 # 每个路径的最大连接

Feign最佳实践方案

Java分布式微服务2——声明式Http客户端(Feign)与网关(Gateway)_第3张图片缺点是会造成紧耦合,并且还需要在实现类中重新写一遍@PathVariable这种注解

Java分布式微服务2——声明式Http客户端(Feign)与网关(Gateway)_第4张图片缺点是会引入大量的方法,但是并不是都能用得上

抽取Feign为单独模块时,要注意到其他微服务的@ComponentScan是只能扫描到同级别及以下的类,为了让其他微服务扫描到Feign模块中的FeignClient,需要在@EnableFeignClients注解上增加参数(推荐第二种)
Java分布式微服务2——声明式Http客户端(Feign)与网关(Gateway)_第5张图片

网关Gateway

网关Gateway的作用与搭建

  • 身份认证,权限校验
  • 服务路由,负载均衡
  • 请求限流
    SpringCloudGateway是响应式编程的网关实现
    搭建步骤:
  1. 新建一个网关的Module,在其中引入依赖
<!--        nacos客户端依赖-->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>

<!--        网关依赖-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-gateway</artifactId>
        </dependency>
  1. 编写路由和Nacos地址(application.yml)
server:
  port: 10010
spring:
  application:
    name: gateway
  cloud:
    nacos:
        server-addr: localhost:8848 # nacos服务器地址
    gateway:
      routes:
        - id: user-service # 路由id,自定义,只要唯一即可
          uri: lb://userservice # 路由的目标地址 lb=LoadBalance负载均衡, 后面跟服务名称,会被nacos注册中心对照为服务地址
          predicates: # 路由断言,也就是判断哪些请求模式是属于这个路由的
            - Path=/user/** 
       
  1. 写好Application启动类

这就搭建完成了,以后请求都发到网关,网关判断后通过注册中心找到对应服务,把请求转过去
Java分布式微服务2——声明式Http客户端(Feign)与网关(Gateway)_第6张图片

路由断言工厂Route Predicate Factory

配置文件中写的断言规则path只是字符串,会被Predicate Factory读取并处理,转变为路由判断条件,之后由对应的断言工厂进行判断,还有其他断言可以使用:
Java分布式微服务2——声明式Http客户端(Feign)与网关(Gateway)_第7张图片

路由过滤器GatewayFilter

网关中的过滤器,可以对进入网关的请求和微服务返回的响应进行处理

Java分布式微服务2——声明式Http客户端(Feign)与网关(Gateway)_第8张图片Java分布式微服务2——声明式Http客户端(Feign)与网关(Gateway)_第9张图片过滤器的添加也是在配置文件.yml中,给某服务加过滤器,就修改之前的配置为:

server:
  port: 10010
spring:
  application:
    name: gateway
  cloud:
    nacos:
        server-addr: localhost:8848 
    gateway:
      routes:
        - id: user-service 
          uri: lb://userservice 
          filter:
            - AddRequestHeader=Greeting, Hello World! # 添加请求头过滤器工厂
          predicates:
            - Path=/user/** 
       

如果想给所有的服务都加过滤器,可以用默认过滤器,对所有路由都生效

spring:
  application:
    name: gateway
  cloud:
    nacos:
        server-addr: localhost:8848 # nacos服务器地址
    gateway:
      routes:
        ......
      default-filters:
        - AddRequestHeader=Greeting, Hello world! # 添加请求头

全局过滤器

全局过滤器也是作用于所有请求和微服务响应,与默认过滤器的区别是,它需要自己使用代码实现其逻辑:

  1. 实现GlobalFilter接口
    Java分布式微服务2——声明式Http客户端(Feign)与网关(Gateway)_第10张图片2. 配置优先级(@Order或者实现Ordered接口)
//@Order(1) 设置过滤器的优先级,越小越高, -1最大,也可以通过实现Ordered接口完成优先级配置
@Component
public class AuthorizeFilter implements GlobalFilterOrdered{
		@Override
		public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain){
				// 1.获取请求参数
				ServerHttpRequest request = exchange.getRequest();
				MultiValueMap<String, String> params = request.getQueryParams();
				// 2.获取参数中的authorization参数
				String authorization = params.getFirst("authorization");
				// 3.判断参数值是否等于admin
				if("admin".equals(authorization)){
					// 4.相等就放行
					return chain.filter(exchange);
				}else{
					// 5.不等就拦截
					// 设置状态码
					exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
					// 拦截
					return exchange.getResponse().setComplete();
				}
		}

		@Override
		public int getOrder(){ return -1;}
}

过滤器执行顺序

三种过滤器是放在一个集合里排序的,排序规则是:

  1. 优先级Order的值
  2. 同优先级按defaultFilter>路由过滤器>GlobalFilter的顺序执行
  3. GlobalFilter优先级是自己指定的,其他两个是按在配置文件中的书写顺序从1递增的(第一个写的过滤器Order=1,第二个写的Order=2)

Java分布式微服务2——声明式Http客户端(Feign)与网关(Gateway)_第11张图片
为什么三种过滤器可以放在一个集合中排序?

  • 路由过滤器和默认过滤器都是GatewayFilter的实现类
  • 全局过滤器GlobalFilter会作为参数交给GatewayFilterAdapter的构造函数,而GatewayFilterAdapter是实现了GatewayFilter接口的,相当于把GlobalFilter装饰为了GatewayFilter的实现类
  • 所以他们三个能以GatewayFilter实现类的身份加入一个集合

网关的跨域处理

跨域问题:浏览器禁止请求发起者与服务端发生跨域ajax请求,请求被浏览器拦截
浏览器采用同源策略,需要网页和其调用的接口的 协议、域名、端口 都一致,不一致它会觉得有风险。
CORS 是一个 W3C 标准,全称是“跨源资源共享”(Cross-origin resource sharing),或者通俗地
称为“跨域资源共享”。它允许浏览器向跨源的服务器,发出XMLHttpRequest请求,从而克服AJAX
只能同源使用的限制。
网关处理跨域采用的就是CORS,只需要在配置中进行添加:

spring:
  cloud:
    gateway:
      globalcors: # 全局的跨域处理
        add-to-simple-url-handler-mapping: true # 解决options请求被拦截问题
        corsConfigurations:
          '[/**]': # 对所有的请求生效
            allowedOrigins: # 允许哪些网站的跨域请求
              - "http://localhost:8090"
              - "http://www.leyou.com"
            allowedMethods: # 允许的跨域ajax的请求方式
              - "GET"
              - "POST"
              - "DELETE"
              - "PUT"
              - "OPTIONS"
            allowedHeaders: "*" # 允许在请求中携带的头信息
            allowCredentials: true # 是否允许携带cookie
            maxAge: 360000 # 这次跨域检测的有效期

你可能感兴趣的:(微服务,Java,java,分布式,微服务)