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

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自定义配置

在这里插入图片描述
方式一:改配置文件

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

方式二:在Configuration类中声明一个对应类型的Bean
在这里插入图片描述

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最佳实践方案

在这里插入图片描述缺点是会造成紧耦合,并且还需要在实现类中重新写一遍@PathVariable这种注解

在这里插入图片描述缺点是会引入大量的方法,但是并不是都能用得上

抽取Feign为单独模块时,要注意到其他微服务的@ComponentScan是只能扫描到同级别及以下的类,为了让其他微服务扫描到Feign模块中的FeignClient,需要在@EnableFeignClients注解上增加参数(推荐第二种)
在这里插入图片描述

网关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启动类

这就搭建完成了,以后请求都发到网关,网关判断后通过注册中心找到对应服务,把请求转过去
在这里插入图片描述

路由断言工厂Route Predicate Factory

配置文件中写的断言规则path只是字符串,会被Predicate Factory读取并处理,转变为路由判断条件,之后由对应的断言工厂进行判断,还有其他断言可以使用:
在这里插入图片描述

路由过滤器GatewayFilter

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

在这里插入图片描述在这里插入图片描述过滤器的添加也是在配置文件.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接口
    在这里插入图片描述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)

在这里插入图片描述
为什么三种过滤器可以放在一个集合中排序?

  • 路由过滤器和默认过滤器都是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 # 这次跨域检测的有效期
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值