【SpringCloud】OpenFeign 远程调用

快速上手

1、引入依赖

调用方的项目工程 pom.xml 添加依赖

<!--openFeign-->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<!--负载均衡器-->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-loadbalancer</artifactId>
</dependency>

父依赖版本管理

    <dependencyManagement>
        <dependencies>
            <!--spring cloud-->
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>2021.0.3</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <!--spring cloud alibaba-->
            <dependency>
                <groupId>com.alibaba.cloud</groupId>
                <artifactId>spring-cloud-alibaba-dependencies</artifactId>
                <version>2021.0.4.0</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
    </dependencyManagement>

2、启动OpenFeign

调用方的启动类上添加 @EnableFeignClients 注解,启动 OpenFeign 功能
@EnableFeignClients注解参数:

  1. basePackages:需要被调用的API的存放位置(当API位置在默认的扫包范围外时需要配置

  2. defaultConfiguration:需要全局启用的配置(如:日志记录、请求拦截、失败回调…

@EnableFeignClients(basePackages = "com.hmall.api.client",defaultConfiguration = DefaultFeignConfig.class)
@SpringBootApplication
@MapperScan("com.hmall.cart.mapper")
public class CartApplication {

    public static void main(String[] args) {
        SpringApplication.run(CartApplication.class, args);
    }
}

3、编写OpenFeign客户端

这里只需要声明接口(被调用方的方法),无需实现方法。接口中的几个关键信息:

  • @FeignClient(“item-service”) :声明服务名称(被调用方
  • @GetMapping :声明请求方式
  • @GetMapping(“/items”) :声明请求路径
  • @RequestParam(“ids”) Collection ids :声明请求参数
  • List :返回值类型
package com.hmall.cart.client;

import com.hmall.cart.domain.dto.ItemDTO;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;

import java.util.List;

@FeignClient("item-service")
public interface ItemClient {

    @GetMapping("/items")
    List<ItemDTO> queryItemByIds(@RequestParam("ids") Collection<Long> ids);
}

有了上述信息,OpenFeign就可以利用动态代理帮我们实现这个方法,并且向http://item-service/items发送一个GET请求,携带ids为请求参数,并自动将返回值处理为List。
我们只需要直接调用这个方法,即可实现远程调用了。

4、使用FeignClient

调用方注入写好的 OpenFeign 客户端,调用客户端内方法即可!
如:我们在 cart-service 的 com.hmall.cart.service.impl.CartServiceImpl 中改造代码,直接调用 ItemClient 的方法:

在这里插入图片描述

在这里插入图片描述

feign替我们完成了服务拉取、负载均衡、发送http请求的所有工作。
而且,这里我们不再需要RestTemplate了,还省去了RestTemplate的注册。

5、使用连接池

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

  • HttpURLConnection:默认实现,不支持连接池
  • Apache HttpClient :支持连接池
  • OKHttp:支持连接池

调用方的 pom.xml 中引入依赖

<!--OK http 的依赖 -->
<dependency>
  <groupId>io.github.openfeign</groupId>
  <artifactId>feign-okhttp</artifactId>
</dependency>

调用方的 application.yml 配置文件中开启 Feign 的连接池功能

feign:
  okhttp:
    enabled: true # 开启OKHttp功能

debug在org.springframework.cloud.openfeign.loadbalancer.FeignBlockingLoadBalancerClient中的execute方法中打断点,即可验证连接池是否生效。

6、日志配置

要让日志级别生效,还需要配置这个类。有两种方式:

  • 局部生效:在某个FeignClient中配置,只对当前FeignClient生效
@FeignClient(value = "item-service", configuration = DefaultFeignConfig.class)
  • 全局生效:在@EnableFeignClients中配置,针对所有FeignClient生效。
@EnableFeignClients(defaultConfiguration = DefaultFeignConfig.class)

7、Feign拦截器

目的:实现微服务之间传递数据,如用户信息

应用场景:下单的过程中,需要调用商品服务扣减库存,调用购物车服务清理用户购物车。而清理购物车时必须知道当前登录的用户身份。但是,订单服务调用购物车时并没有传递用户信息,购物车服务无法知道当前用户是谁!

这是,Feign 中的拦截器接口:feign.RequestInterceptor就发挥作用了

public interface RequestInterceptor {

  /**
   * Called for every request. 
   * Add data using methods on the supplied {@link RequestTemplate}.
   */
  void apply(RequestTemplate template);
}

我们只需要实现这个接口,然后实现 apply 方法,利用 RequestTemplate 类来添加请求头,将用户信息保存到请求头中。这样以来,每次 OpenFeign 发起请求的时候都会调用该方法,传递用户信息。
(由于 FeignClient 全部都是在 hm-api 模块,因此在 hm-api 模块的com.hmall.api.config.DefaultFeignConfig 中编写这个拦截器)

@Bean
public RequestInterceptor userInfoRequestInterceptor(){
    return new RequestInterceptor() {
        @Override
        public void apply(RequestTemplate template) {
            // 获取登录用户
            Long userId = UserContext.getUser();
            if(userId == null) {
                // 如果为空则直接跳过
                return;
            }
            // 如果不为空则放入请求头中,传递给下游微服务
            template.header("user-info", userId.toString());
        }
    };
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值