远程调用Feign

Feign远程调用,核心就是通过一系列的封装和处理,将以JAVA注解的方式定义的远程调用API接口,最终转换成HTTP的请求形式,然后将HTTP的请求的响应结果,解码成JAVA Bean,返回给调用者。

1 Feign基础使用

1.1 导入依赖

在消费者工程service-consumer中导入Feign依赖信息:

<dependency>
    <groupId>org.springframework.cloudgroupId>
    <artifactId>spring-cloud-starter-openfeignartifactId>
dependency>
1.2 客户端接口实现

在消费者工程service-consumer中实现Feign客户端接口:

    package com.giser.consumer.feign;
    
    import com.giser.consumer.pojo.User;
    import org.springframework.cloud.openfeign.FeignClient;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.PathVariable;
    
    @FeignClient(value="user-service")
    public interface UserFeignClient {
    
        @GetMapping("/user/{id}")
        User queryById(@PathVariable("id") Long id);
    
    }
  • 编写FeignClient,作为一个接口,Feign会通过动态代理生成实现类;
  • 通过@FeignClient标识当前接口为Feign客户端,同时通过value属性指定服务名称;
  • 接口中定义的方法可以使用SpringMVC中的注解,实现方法映射,Feign会根据注解拼接访问地址,并请求服务,将响应结果返回。
1.3 编写控制器
    package com.giser.consumer.controller;
    
    import com.giser.consumer.feign.UserFeignClient;
    import com.giser.consumer.pojo.User;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.PathVariable;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RestController;
    
    @RestController
    @RequestMapping("cf")
    public class ConsumerFeignController {
    
        @Autowired
        private UserFeignClient userFeignClient;
    
        @GetMapping("/{id}")
        public User queryById(@PathVariable Long id){
            return userFeignClient.queryById(id);
        }
    
    }
1.4 开启Feign
    package com.giser.consumer;
    
    import org.springframework.boot.SpringApplication;
    import org.springframework.cloud.client.SpringCloudApplication;
    import org.springframework.cloud.client.loadbalancer.LoadBalanced;
    import org.springframework.cloud.openfeign.EnableFeignClients;
    import org.springframework.context.annotation.Bean;
    import org.springframework.web.client.RestTemplate;
    
    @SpringCloudApplication
    @EnableFeignClients //	开启Feign
    public class ConsumerApplication {
        public static void main(String[] args) {
            SpringApplication.run(ConsumerApplication.class, args);
        }
        @Bean
        @LoadBalanced
        public RestTemplate restTemplate(){
            return new RestTemplate();
        }
    }
1.5 服务测试

启动EurekaServer、UserService、ConsumerService服务,访问http://localhost:8081/cf/1进行测试。

2 负载均衡

在Feign中已经集成了Ribbon依赖和自动配置。
Feign内置的Ribbon默认了请求超时时长为1000,在服务消费工程service-consumer中,可以通过以下配置修改:

    ribbon:
      ConnectTimeout: 1000 # 连接超时时长
      ReadTimeout: 2000 # 数据通信超时时长
      MaxAutoRetries: 0 # 当前服务器的重试次数
      MaxAutoRetriesNextServer: 0 # 重试多少次服务
      OkToRetryOnAllOperations: false # 是否对所有的请求方式都重试

Ribbon内部有重试机制,如果不希望重试,则可以添加ribbon.OkToRetryOnAllOperations=false配置。

3 支持Hystrix

Feign默认也集成了Hystrix,不过默认时关闭的,如需开启可以通过以下配置:

    feign:
      hystrix:
        enabled: true

此时对于Feign中的fallback需要通过类来实现:

  • 定义fallback处理类
    package com.giser.consumer.fallback;
    
    import com.giser.consumer.feign.UserClient;
    import com.giser.consumer.pojo.User;
    import org.springframework.stereotype.Component;
    
    @Component
    public class UserClientFallback implements UserClient {
        @Override
        public User queryById(Long id) {
            User user = new User();
            user.setId(id);
            user.setUsername("用户异常");
            return user;
        }
    }
  • 在FeignClient中配置Fallback类
    package com.giser.consumer.feign;
    
    import com.giser.consumer.fallback.UserClientFallback;
    import com.giser.consumer.pojo.User;
    import org.springframework.cloud.openfeign.FeignClient;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.PathVariable;
    
    @FeignClient(value="user-service", fallback = UserClientFallback.class)
    public interface UserClient {
    
        @GetMapping("/user/{id}")
        User queryById(@PathVariable("id") Long id);
    
    }
  • 启动测试

4 请求压缩

SpringCloud Feign支持对请求和响应进行GZIP压缩,以减少通信过程中的性能损耗。

  • 开启请求与响应的压缩功能
    feign:
      compression:
        request:
          enabled: true # 开启请求压缩
        response:
          enabled: true
  • 设置请求的数据类型及触发压缩的大小下限
    feign:
      compression:
        request:
          enabled: true # 开启请求压缩
          mime-types: text/html,application/xml,application/json # 设置压缩的数据类型
          min-request-size: 2048 # 设置触发压缩的大小下限

5 日志级别

由于@FeignClient 注解修改的客户端在被代理时,都会创建一个新的Fegin.Logger实例,因此通过logging.level.xx=debug 来设置日志级别对Fegin客户端而言不会产生效果,需要额外指定这个日志的级别。

在service-consumer中的yml中配置日志级别:

    logging:
      level:
        com.giser: debug

在service-consumer中编写FeignLogConfig类,定义日志级别:

    package com.giser.consumer.config;
    
    import feign.Logger;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    
    @Configuration
    public class FeignLogConfig {
        @Bean
        Logger.Level feignLoggerLevel(){
            return Logger.Level.FULL;
        }
    }

Feign支持四种Level级别,包括:

  • NONE:不记录任何日志信息,这是默认值。

  • BASIC:仅记录请求的方法,URL以及响应状态码和执行时间

  • HEADERS:在BASIC的基础上,额外记录了请求和响应的头信息

  • FULL:记录所有请求和响应的明细,包括头信息、请求体、元数据。

    在@FeignClient注解中指定配置类:

    package com.giser.consumer.feign;
    
    import com.giser.consumer.config.FeignLogConfig;
    import com.giser.consumer.fallback.UserClientFallback;
    import com.giser.consumer.pojo.User;
    import org.springframework.cloud.openfeign.FeignClient;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.PathVariable;
    
    @FeignClient(value="user-service", fallback = UserClientFallback.class, configuration = FeignLogConfig.class)
    public interface UserClient {
    
        @GetMapping("/user/{id}")
        User queryById(@PathVariable("id") Long id);
    
    }

重启项目,进行服务访问,可以看到类似如下日志信息:

   [UserClient#queryById] ---> GET http://user-service/user/3 HTTP/1.1
    [UserClient#queryById] Accept-Encoding: deflate
    [UserClient#queryById] Accept-Encoding: gzip
    [UserClient#queryById] ---> END HTTP (0-byte body)
    
    [UserClient#queryById] <--- HTTP/1.1 200 (888ms)
    [UserClient#queryById] content-type: application/json;charset=UTF-8
    [UserClient#queryById] date: Sat, 16 Oct 2021 05:51:53 GMT
    [UserClient#queryById] transfer-encoding: chunked
    [UserClient#queryById] 
    [UserClient#queryById] {"id":3,"username":"wangwu","password":"666"}
    [UserClient#queryById] <--- END HTTP (45-byte body)

你可能感兴趣的:(#,SpringCloud,Feign)