【MSA】Spring cloud OpenFeign

发布时间 2023-06-21 08:49:40作者: lihewei

1. Feign 简介

​ Feign 是声明性(注解)Web 服务客户端。它使编写 Web 服务客户端更加容易。要使用 Feign,请创建一个接口并对其进行注解。它具有可插入注解支持,包括 Feign 注解和 JAX-RS 注解。Feign 还支持可插拔编码器和解码器。Spring Cloud 添加了对 Spring MVC 注解的支持,并支持使用 HttpMessageConverters,Spring Web 中默认使用的注解。Spring Cloud 集成了 Ribbon 和 Eureka 以及 Spring Cloud LoadBalancer,以在使用 Feign 时提供负载平衡的 http 客户端。

Feign 是一个远程调用的组件 (接口,注解) http 调用的,Feign 集成了 ribbon ,ribbon 里面集成了 eureka

2. Feign 快速入门

实现步骤:

  1. 导入依赖feign的starter
  2. 启动引导类加@EnableFeignClients注解
  3. 编写FeignClient接口,使用SpringMVC的注解
  4. 在Controller中注入Feign接口,直接调用,无需实现类
  5. 访问接口测试

实现过程:

1. 导入依赖feign的starter (导入到消费者中)

<!--配置feign-->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>

2. 编写服务提供者provider-order-service

  • 修改服务提供者配置文件

    server:
    	port: 8081
    spring:
    	application:
    		name: provider-order-service
    eureka:
    	client:
    		service-url:
    			defaultZone: http://localhost:8761/eureka
    instance:
    	instance-id: ${spring.application.name}:${server.port}
    	prefer-ip-address: true
    
  • 修改启动类

    @SpringCloudApplication
    @EnableFeignClients//开启Feign功能 开启当前服务的feign客户端支持,feign底层封装了一个请求的客户端(RestTemplate【httpclient,okhttp,..】
    public class ProviderApplication {
        public static void main(String[] args) {
            SpringApplication.run(ConsumerApplication.class,args);
        }
    }
    
  • 增加一个访问接口

    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.RestController;
    
    @RestController
    public class OrderController {
    	/**
    	* 订单服务下单接口
    	* @return
    	*/
    	@GetMapping("doOrder")
    	public String doOrder() {
    		System.out.println("有用户来下单了");
    		return "下单成功";
    	}
    }
    

3. 编写服务消费者consumer-user-service

  • 修改服务消费者配置文件

    server:
    	port: 8081
    spring:
    	application:
    		name: consumer-user-service
    eureka:
    	client:
    		service-url:
    			defaultZone: http://localhost:8761/eureka
    	instance:
    		instance-id: ${spring.application.name}:${server.port}
    		prefer-ip-address: true
    
  • 创建远程调用的Feign接口

    package com.lihw.feign;
    import org.springframework.cloud.openfeign.FeignClient;
    import org.springframework.web.bind.annotation.GetMapping;
    /**
    * @FeignClient 声明是 feign 的调用
    * value = "provider-order-service" value 后面的值必须和提供者的服
    务名一致
    */
    @FeignClient(value = "provider-order-service")
    public interface UserOrderFeign {
      
    	/**
    	* 描述: 下单的方法 这里的路径必须和提供者的路径一致
    	* @return java.lang.String
    	*/
    	@GetMapping("doOrder")
      	String doOrder();
    }
    
  • 创建Controller

    import com.bjpowernode.feign.UserOrderFeign;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.RestController;
    
    @RestController
    public class UserController {
    	@Autowired
    	private UserOrderFeign userOrderFeign;
      
    	/**
    	* 用户远程调用下单的接口
    	* @return
    	*/
    	@GetMapping("userDoOrder")
    	public String userDoOrder() {
    		String result = userOrderFeign.doOrder();
    		System.out.println(result);
    		return result;
    	}
    }
    
  • 修改consumer-user-service启动类

    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
    import org.springframework.cloud.openfeign.EnableFeignClients;
    
    @SpringBootApplication
    @EnableEurekaClient
    @EnableFeignClients //标记 feign 的客户端
    public class ConsumerUserServiceApplication {
      	public static void main(String[] args) {
    		SpringApplication.run(ConsumerUserServiceApplication.class, args);
    	}
    }
    

4. 测试

访问:http://localhost:8081/userDoOrder

consumer-user-service ---> /userDoOrder ---> 通过 feign 调用 /doOrder ---> provider-order-service 下单成功

3. Feign 调用参数处理

3.1 传参问题

Feign 传参确保消费者和提供者的参数列表一致 包括返回值 方法签名要一致

  1. 通过 URL 传参数,GET 请求,参数列表使用@PathVariable(“”)
  2. 如果是 GET 请求,每个基本参数必须加@RequestParam(“”)
  3. 如果是 POST 请求,而且是对象集合等参数,必须加@Requestbody 或者@RequestParam

3.2 时间日期参数问题

使用 feign 远程调用时,传递 Date 类型,接收方的时间会相差 14 个小时,是因为时区造成的

处理方案:

  1. 使用字符串传递参数,接收方转换成时间类型(推荐使用)不要单独传递时间
  2. 使用 JDK8 的 LocalDate(日期) 或 LocalDateTime(日期和时间,接收方只有秒,没有毫秒)
  3. 自定义转换方法

传参总结:

get 请求只用来传递基本参数 而且加注解@RequestParam

post 请求用来传递对象参数 并且加注解@RequestBody

4. Feign日志功能

日志级别:

  • NONE 默认的,不显示日志

  • BASE 仅记录请求方法,URL ,响应状态码及执行时间

  • HEADERS 在 BASE 之上增加了请求和响应头的信息

  • FULL 在 HEADERS 之上增加了请求和响应的正文及无数据

创建配置类:

package com.bjpowernode.config;
import feign.Logger;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class FeignConfig {
  
	@Bean
	Logger.Level feignLogger() {
	return Logger.Level.FULL;	
    }
}

修改配置文件

logging:
	level:
		com.bjpowernode.feign.UserOrderFeign: debug