Feign远程调用

绝地灬酷狼 2023-10-04 20:35 99阅读 0赞

Feign远程调用

1. 为什么要使用Feign

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

在这里插入图片描述

存在下面的问题:

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

• 参数复杂URL难以维护

Feign是一个声明式的http客户端,官方地址:https://github.com/OpenFeign/feign

其作用就是帮助我们优雅的实现http请求的发送,解决上面提到的问题。
在这里插入图片描述

2. Feign替代RestTemplate

使用步骤如下:

第一步:引入feign的依赖

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

第二步:在启动类添加开启Feign注解: @EnableFeignClients

  1. @SpringBootApplication
  2. @MapperScan("com.suke.shop.order.mapper")
  3. @EnableFeignClients
  4. public class OrderApplication {
  5. public static void main(String[] args) {
  6. SpringApplication.run(OrderApplication.class,args);
  7. }
  8. @Bean
  9. @LoadBalanced
  10. public RestTemplate restTemplate() {
  11. return new RestTemplate();
  12. }
  13. @Bean
  14. public IRule randomRule(){
  15. return new RandomRule();
  16. }
  17. }

第三步:编写Feign的客户端

  1. @RequestMapping("user")
  2. @FeignClient("userservice")
  3. public interface UserClient {
  4. @GetMapping("/users/{id}")
  5. User findById(@PathVariable("id") Integer id);
  6. }

这个客户端主要是基于SpringMVC的注解来声明远程调用的信息,比如:

  • 服务名称:userservice
  • 请求方式:GET
  • 请求路径:/user/users/{id}
  • 请求参数:Integer id
  • 返回值类型:User

这样,Feign就可以帮助我们发送http请求,无需自己使用RestTemplate来发送了。

第四步: 替换Service实现类使用RestTemplate远程调用userservice的代码

  1. @Service
  2. public class OrderServiceImpl implements OrderService {
  3. @Autowired
  4. private OrderMapper orderMapper;
  5. /*@Autowired
  6. private RestTemplate restTemplate;*/
  7. @Autowired
  8. private UserClient userClient;
  9. @Override
  10. public Order queryOrderById(Integer oid) {
  11. //1.查询订单
  12. Order order = orderMapper.selectById(oid);
  13. //2.根据userId查询用户
  14. //String url = "http://localhost:7777/user/users/"+order.getUid();
  15. /*String url="http://userservice/user/users/"+order.getUid();
  16. User user = restTemplate.getForObject(url, User.class);*/
  17. User user = userClient.findById(order.getUid());
  18. //3.设置user
  19. order.setUser(user);
  20. return order;
  21. }
  22. }

是不是看起来优雅多了。

3. Feign自定义配置

Feign可以支持很多的自定义配置,如下表所示:




































类型 作用 说明
feign.Logger.Level 修改日志级别 包含四种不同的级别:NONE、BASIC、HEADERS、FULL
feign.codec.Decoder 响应结果的解析器 http远程调用的结果做解析,例如解析json字符串为java对象
feign.codec.Encoder 请求参数编码 将请求参数编码,便于通过http请求发送
feign. Contract 支持的注解格式 默认是SpringMVC的注解
feign. Retryer 失败重试机制 请求失败的重试机制,默认是没有,不过会使用Ribbon的重试

注意:

一般情况下,默认值就能满足我们使用

3.1 自定义配置

第一种: 配置文件方式

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

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

在这里插入图片描述

而日志的级别分为四种:

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

也可以针对所有服务:

  1. feign:
  2. client:
  3. config:
  4. default: # 这里用default就是全局配置,如果是写服务名称,则是针对某个微服务的配置
  5. loggerLevel: FULL # 日志级别

第二种方式: java编码实现

基于Java代码来修改日志级别,先声明一个类,然后声明一个Logger.Level的对象:

  1. public class MyFeignConfiguration {
  2. @Bean
  3. public Logger.Level feignLogLevel(){
  4. return Logger.Level.BASIC; // 日志级别为BASIC
  5. }
  6. }

如果要全局生效,将其放到启动类的@EnableFeignClients这个注解中:

  1. @EnableFeignClients(defaultConfiguration = MyFeignConfiguration.class)

如果是局部生效,则把它放到对应的@FeignClient这个注解中:

  1. @FeignClient(value = "userservice", configuration = MyFeignConfiguration.class)

4. Feign使用优化

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

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

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

我们的课件使用HttpClient

第一步: 引入HttpClient依赖

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

第二步: 配置连接池

在shop-order的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 # 每个路径的最大连接数

源码分析:

接下来,在FeignClientFactoryBean中的loadBalance方法中打断点:以debug重启shop-order:

在这里插入图片描述

我们发现我们使用client是HttpClient

经验:

1.日志级别尽量用basic

2.使用HttpClient或OKHttp代替URLConnection

5. Feign 最佳应用

所谓 最佳应用,就是使用过程中总结的经验,最好的一种使用方式。

自习观察可以发现,Feign的客户端与服务提供者的controller代码非常相似:

在这里插入图片描述

有没有一种办法简化这种重复的代码编写呢?

我们可以将Feign的Client抽取为独立模块,并且把接口默认的Feign配置都放到这个模块中,并且依赖我们common模块,提供给所有消费者使用。

例如,将UserClient、Feign的默认配置都抽取到一个feign-api包中,所有微服务引用该依赖包,即可直接使用。

在这里插入图片描述

步骤:

第一步: 首先创建一个module,命名为feign-api:
在这里插入图片描述

第二步: 在feign-api中然后引入feign的starter依赖以及shop-common

  1. <dependencies>
  2. <!--OpenFeign -->
  3. <dependency>
  4. <groupId>org.springframework.cloud</groupId>
  5. <artifactId>spring-cloud-starter-openfeign</artifactId>
  6. </dependency>
  7. <dependency>
  8. <groupId>org.example</groupId>
  9. <artifactId>shop-common</artifactId>
  10. <version>1.0-SNAPSHOT</version>
  11. </dependency>
  12. </dependencies>

第三步: 把shop-order中的UserClient的代码拷贝到feign-api模块中

在这里插入图片描述

第四步: 在其他服务引入feign-api依赖,并去掉shop-common依赖

  1. <!--feign-api-->
  2. <dependency>
  3. <groupId>org.example</groupId>
  4. <artifactId>feign-api</artifactId>
  5. <version>1.0-SNAPSHOT</version>
  6. </dependency>

第五步: 把其他服务器中的XxxClient以及配置类删除,引用feign-api的类
在这里插入图片描述

但是我们发现userClient报错:这是因为UserClient现在在com.suke.shop.client.Us包下,

而shop-order的@EnableFeignClients注解是在com.suke.shop.order包下,不在同一个包,无法扫描到UserClient。

解决扫描包问题方案:

  1. 指定Feign应该扫描的包:

    @EnableFeignClients(“com.suke.shop.client”)

  2. 指定需要加载的Client接口

    @EnableFeignClients(clients={

    1. UserClient.class})

rClient现在在com.suke.shop.client.Us包下,

而shop-order的@EnableFeignClients注解是在com.suke.shop.order包下,不在同一个包,无法扫描到UserClient。

解决扫描包问题方案:

  1. 指定Feign应该扫描的包:

    @EnableFeignClients(“com.suke.shop.client”)

  2. 指定需要加载的Client接口

    @EnableFeignClients(clients={

    1. UserClient.class})

发表评论

表情:
评论列表 (有 0 条评论,99人围观)

还没有评论,来说两句吧...

相关阅读

    相关 Feign远程调用

    1. Feign远程调用 > 为啥需要学Feign呢?我们先来回顾之前写的代码 先来看我们以前利用RestTemplate发起远程调用的代码: ![img][] 这

    相关 Feign远程调用

    Feign远程调用 先来看我们以前利用RestTemplate发起远程调用的代码: ![\[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-