Feign 的英文表意为“假装,伪装,变形”,它是一个声明式的伪Http客户端,它是一个对http请求调用的轻量级框架.Feign使得写Http客户端变得更简单,我们只需要创建一个接口并注解,将请求模板化,当实际调用的时候,传入参数,根据参数再应用到请求上,进而转化成真正的请求,这种请求相对而言比较直观.Feign默认集成了Ribbon,并和Eureka结合,默认实现了负载均衡的效果.
2. Feign的特点-
1️⃣. Feign 采用的是基于接口的注解;
-
2️⃣. Feign 整合了ribbon,具有负载均衡的能力;
-
3️⃣. 整合了Hystrix,具有熔断的能力.
封装了Http调用流程,更适合面向接口的编程习惯.
在服务调用的场景中,我们经常调用基于Http协议的服务,而我们经常使用到的框架可能有HttpURLConnection、Apache HttpComponnets、OkHttp3 、Netty等,这些框架都有自身的特性,但是从角色划分上来看,他们的职能是一致的,都是用来提供Http调用服务的.具体流程如下:
FeignClient 会在底层根据我们的注解,与我们指定的服务建立连接、构造请求、发起请求、获取响应、解析响应,等,这一系列的工作,Feign 全帮我们实现了.
那么Feign 是如何做到这些的呢?Feign 的一个关键机制就是使用了动态代理.
-
首先,如果我们对某个接口定义了 @FeignClient注解,Feign就会针对这个接口创建一个动态代理;
-
然后我们要是调用了那个接口,本质就是调用 Feign 创建的动态代理,这是核心中的核心;
-
Feign的动态代理会根据我们在接口上使用的 @RequestMapping 等注解,来动态构造出我们要请求的服务的地址;
-
最后针对这个地址,发起请求、解析响应.

Feign 整体框架非常小巧,在处理请求转换和消息解析的过程中,基本上没什么时间消耗.真正影响性能的,是处理Http请求的环节.
如上所述,由于默认情况下,Feign采用的是JDK的HttpURLConnection,所以整体性能并不高.
四. Feign代码实战在前一篇博客的基础之上,创建出一个基于Feign组件的eureka client模块-->service_feign_consumer.
1. 添加依赖包
org.springframework.cloud
spring-cloud-starter-netflix-eureka-client
org.springframework.cloud
spring-cloud-starter-openfeign
2. 创建配置文件
server:
port: 8765
spring:
application:
name: eureka-feign
eureka:
instance:
hostname: localhost
client:
serviceUrl:
defaultZone: http://localhost:8761/eureka/
3. 创建调用远程服务的service接口
定义一个feign接口,通过@ FeignClient(“要调用的服务名”),来指定调用哪个服务.比如在代码中调用了eureka-provider服务的“/hello”接口.
package com.syc.cloud.service;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
@FeignClient(value = "eureka-provider")
public interface FeignHelloService {
@RequestMapping(value = "/hello", method = RequestMethod.GET)
String sayHello(@RequestParam(value = "name") String name);
}
3.1 @FeignClient标签的常用属性如下:
name: 指定FeignClient的名称,如果项目使用了Ribbon,name属性会作为微服务的名称,用于服务发现;
url: url一般用于调试,可以手动指定@FeignClient调用的地址;
decode404: 当发生http 404错误时,如果该字段为true,会调用decoder进行解码,否则抛出FeignException;
configuration: Feign配置类,可以自定义Feign的Encoder、Decoder、LogLevel、Contract;
fallback: 定义容错的处理类,当调用远程接口失败或超时时,会调用对应接口的容错逻辑,fallback指定的类必须实现@FeignClient标记的接口;
fallbackFactory: 工厂类,用于生成fallback类示例,通过这个属性我们可以实现每个接口通用的容错逻辑,减少重复的代码;
path: 定义当前FeignClient的统一前缀.
4. 创建web层实现
Web层对外暴露一个"/hello"的API接口,通过上面定义的Feign客户端FeignHelloService 来消费服务.
package com.syc.cloud.web;
import com.syc.cloud.service.FeignHelloService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class HelloController {
//编译器报错,无视即可,因为这个Bean是在程序启动的时候注入的,编译器感知不到,所以报错.
@Autowired
private FeignHelloService helloService;
@GetMapping(value = "/hello")
public String sayHi(@RequestParam String name) {
return helloService.sayHello(name);
}
}
5. 创建入口类
在程序的启动类ServiceFeignApplication,加上@EnableFeignClients注解开启Feign的功能.
package com.syc.cloud;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.cloud.openfeign.EnableFeignClients;
@SpringBootApplication
@EnableEurekaClient
@EnableDiscoveryClient
@EnableFeignClients
public class FeignApplication {
public static void main(String[] args) {
SpringApplication.run(FeignApplication.class, args);
}
}
注意:
入口类上必须添加@EnableDiscoveryClient @EnableFeignClients注解.
6. 目录结构


实现了远程调用,并且实现了负载均衡.