Feign
简介
Feign
是 Netflix
开发的声明式、模板化的 HTTP
客户端,它使得 HTTP
请求变得更简单,Feign
底层的使用的 HTTP
通信框架是 HttpClient
。Feign
默认集成了Ribbon
和 Hystrix
,并和 Eureka
结合,默认实现了负载均衡的效果
Feign
的英文表意为“假装,伪装,变形”, 是一个 http
请求调用的轻量级框架,可以以 Java
接口注解的方式调用 Http
请求,而不用像 Java
中通过封装 HTTP
请求报文的方式直接调用。Feign
通过处理注解,将请求模板化,当实际调用的时候,传入参数,根据参数再应用到请求上,进而转化成真正的请求,这种请求相对而言比较直观
Feign
被广泛应用在 springCloud
的解决方案中,是学习基于 springCloud
微服务架构不可或缺的重要组件
开源项目地址:
https://github.com/OpenFeign/feign
Feign
组件的使用示例
导入依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
在主启动类上开启 Feign
@SpringBootApplication
@EnableEurekaClient
@EnableFeignClients // 在主启动类上开启 Feign
public class UserApplication {
private static final Logger log = LoggerFactory.getLogger(UserApplication.class);
public static void main(String[] args) {
SpringApplication.run(UserApplication.class, args);
log.info("===============springcloud user启动了=================");
}
}
编写服务提供者
@Controller
@RequestMapping(path = {
"/activity" })
public class ActivityController {
private static final Logger log = LoggerFactory.getLogger(ActivityController.class);
@RequestMapping(path = {
"/getCoupon" }, method = RequestMethod.POST)
@ResponseBody
public String getCoupon(@RequestBody Integer id) {
log.info("=============该用户首次登陆(注册),领取优惠券成功,id的值为:" + id + "============");
return "SUCCESS";
}
@RequestMapping(path = {
"/getCouponTimeOut" }, method = RequestMethod.POST)
@ResponseBody
public String getCouponTimeOut(@RequestBody Integer id) {
try {
Random random = new Random();
TimeUnit.SECONDS.sleep(random.nextInt(10) % (7) + 4);
} catch (InterruptedException e) {
e.printStackTrace();
}
log.info("=============该用户首次登陆(注册),领取优惠券失败============");
return "ERROR";
}
}
编写 Feign
调用接口
@FeignClient(name = "STUDY-ACTIVITY", fallback = UserFeignFallback.class)
public interface UserFeign {
@RequestMapping(path = {
"/activity/getCoupon" }, method = RequestMethod.POST)
String getCoupon(@RequestBody Integer id);
@RequestMapping(path = {
"/activity/getCouponTimeOut" }, method = RequestMethod.POST)
String getCouponTimeOut(@RequestBody Integer id);
}
fallback
容错的处理类
fallback
容错的处理类:当调用远程接口失败或超时时(默认的超时时间是1000 ms
,可以自行设置),会调用对应接口的容错逻辑,fallback
指定的类必须实现 @FeignClient
标记的接口
对于每一个标有注解 @FeignClient
的接口,它下面每一个抽象方法都默认被 Hystrix
包裹了
@Component
public class UserFeignFallback implements UserFeign {
@Override
public String getCoupon(Integer id) {
return null;
}
@Override
public String getCouponTimeOut(Integer id) {
return null;
}
}
使用 Feign
接口的实现类调用远程微服务
@Service
public class UserServiceImpl implements UserService {
@Autowired
private UserFeign userFeign;
@Override
public String firstLogin(Integer id) {
String result = userFeign.getCoupon(id);
log.info("===================result的值为:" + result + "======================");
return result;
}
@Override
public String firstLoginTimeOut(Integer id) {
String result = userFeign.getCouponTimeOut(id);
log.info("===================result的值为:" + result + "======================");
return result;
}
}
@FeignClient
注解参数
@FeignClient
注解被@Target(ElementType.TYPE)
修饰,表示FeignClient
注解的作用在目标接口上name
:指定FeignClient
的名称,如果项目使用了Ribbon
,name
属性会作为微服务的名称,用于服务发现url
:一般用于调试,可以手动指定@FeignClient
调用的地址decode404
:当发生http 404
错误时,如果该字段位true
,会调用decoder
进行解码,否则抛出FeignException
configuration
:Feign
配置类,可以自定义Feign
的Encoder、Decoder、LogLevel、Contract
fallback
:定义容错的处理类,当调用远程接口失败或超时时(默认的超时时间是1000ms
,可以自行设置),会调用对应接口的容错逻辑,fallback
指定的类必须实现@FeignClient
标记的接口fallbackFactory
:工厂类,用于生成fallback
类示例,通过这个属性我们可以实现每个接口通用的容错逻辑,减少重复的代码path
:定义当前FeignClient
的统一前缀
Feign
解决了什么问题
封装了 Http
调用流程,更适合面向接口化的编程习惯
在服务调用的场景中,我们经常调用基于 Http
协议的服务,而我们经常使用到的框架可能有 HttpURLConnection、Apache HttpComponnets、OkHttp3 、Netty
等等,这些框架在基于自身的专注点提供了自身特性。而从角色划分上来看,他们的职能是一致的提供Http
调用服务。具体流程如下:
Feign
是如何设计的
默认情况下,Feign
采用的是 JDK
的 HttpURLConnection
的请求调用框架
Feign
的工作原理流程
- 首先通过
@EnableFeignCleints
注解开启FeignCleint
- 根据
Feign
的规则实现接口,并加@FeignCleint
注解 - 服务启动后,会扫描所有的
@ FeignCleint
的注解的接口,并将这些信息注入到spring IOC
容器中 - 当接口的方法被调用时,会通过
JDK
的动态代理,来生成具体的RequesTemplate
对象(该对象封装了HTTP
请求需要的全部信息,包括请求参数名、请求方法等信息,Feign
的模板化就体现在这里) RequesTemplate
再生成Request
Request
交给HttpClient
去处理,其中HttpClient
是JDK
的HttpURLConnection
- 最后
HttpClient
被封装到LoadBalanceClient
类,这个类结合类Ribbon
做到了负载均衡
Feign,Ribbon,Hystrix
三者之间的作用和关系
- 在
springCloud
微服务体系下,微服务之间的互相调用可以通过Feign
进行声明式调用,在这个服务调用过程中Feign
会通过Ribbon
从服务注册中心获取目标微服务的服务器地址列表,之后在网络请求的过程中Ribbon
就会将请求以负载均衡的方式打到微服务的不同实例上,从而实现springCloud
微服务架构中最为关键的功能即服务发现及客户端负载均衡调用 - 另一方面微服务在互相调用的过程中,为了防止某个微服务的故障消耗掉整个系统所有微服务的连接资源,所以在实施微服务调用的过程中我们会要求在调用方实施针对被调用微服务的熔断逻辑。而要实现这个逻辑场景在
springCloud
微服务框架下我们是通过Hystrix
这个框架来实现的 - 调用方会针对被调用微服务设置调用超时时间,一旦超时就会进入熔断逻辑,而这个故障指标信息也会返回给
Hystrix
组件,Hystrix
组件会根据熔断情况判断被调微服务的故障情况从而打开熔断器,之后所有针对该微服务的请求就会直接进入熔断逻辑,直到被调微服务故障恢复,Hystrix
断路器关闭为止