SpringCloud中的OpenFeign以及与Feign的区别_易柏州Innovation
SpringCloud中的OpenFeign以及与Feign的区别
?
?
为什么要学这个?你不想面试的时候多装两个逼多拿两千块钱?
先回顾一下我们之前调用服务的原理SpringCloud中的Ribbon负载均衡。使用RestTemplate加上@loadBalance注解就可以通过服务名加上负载均衡策略去调用远程的服务。
首先这样的写法没有什么问题,工作中也有不少公司是这样干。但我们想一下
1.如果远程服务很多,要维护的服务名也就很多,很容易引起调用的问题。
2.再一点来说,有没有觉得RestTemplate这样的写法很傻逼呢?总感觉不符合我们编码的规范。
OpenFeign组件就解决了我们的问题,面向接口编程。也就是说,咱们把注册中心中每一个服务都以一个接口的形式体现,我们服务的消费者只需要调用这个接口中的方法,配合Ribbon使用,那么底层就会自动的调用远方的服务。 下面我展示用法和原理。咱们不单要会用,也要了解一点原理。
?
那OpenFeign和Feign的区别:
Feign是SpringCloud中的一个轻量级RestFul的Http客户端,内置了Ribbon,用于客户端负载均衡,使用方法是使用Feign的注解去修饰一个接口,客户端调用这个接口那么久是调用远程的微服务了。
OpenFeign在Feign的基础上支持了SpringMVC的注解,如@RequestMapping等。OpenFeign的@FeigenClient注解可以解析SpringMvc的@RequestMapping注解下的接口,通过动态代理的方式产生实现类,实现类中进行负载均衡的微服务远程调用!
看不懂是吧,我们直接上代码。
1.这里我们学习一下OpenFeign的用法(注意OpenFeign是用在服务消费端)。
@SpringBootApplication
@EnableFeignClients 在消费端的主启动类上加上@EnableFeignClients 注解,
表示此服务开启的Feign组件
public class DeptConsumer_80 {
public static void main(String[] args) {
SpringApplication.run(DeptConsumer_80.class, args);
}
}
这里是消费端的代码!
定义一个接口 用@FeignClient修饰,@FeignClient注解的value属性值
填写当前我这个接口对应的哪个微服务,也就是微服务在注册中心中的名称。
可以理解为这一个接口就对应一个微服务了。
那这个接口中对应的方法是什么呢?可以他妈的乱定义吗?
不行,方法必须对应消费端的Controller层的暴露出来的接口以及URL地址。
@Component
@FeignClient(value = "SPRINGCLOUD-PROVIDER-DEPT")
public interface MyTestOpenFeign01 {
@GetMapping("/testOpenFeign01")
String testOpenFeign01();
@GetMapping("/testOpenFeign02")
String testOpenFeign02();
}
这里是服务端的代码!
这是服务端暴露出来的两个接口 URL分别是/testOpenFeign01,/testOpenFeign02。
如果我们在上面的消费端Feign接口中想调用到这两个接口,那上面的MyTestOpenFeign01 接口中
的两个方法也必须打上@GetMapping注解,Url也要一一对应!
@RestController
public class DeptController {
@Autowired
private DeptService deptService;
@GetMapping("/testOpenFeign01")
public String testOpenFeign01(){
return deptService.testOpenFeign01();
}
@GetMapping("/testOpenFeign02")
public String testOpenFeign02(){
return deptService.testOpenFeign02();
}
最后是消费端的Controller层,我们把我们刚刚定义的MyTestOpenFeign01注入进来
调用接口中的方法,他就会自动的默认的以负载均衡的方式远程调用到了服务端的"/testOpenFeign01"
和"/testOpenFeign02"接口
@RestController
public class OpenFeignController {
@Autowired
private MyTestOpenFeign01 myTestOpenFeign01;
@RequestMapping("/consumer/testOpenFeign01")
public String testOpenFeign01(){
return myTestOpenFeign01.testOpenFeign01();
}
@RequestMapping("/consumer/testOpenFeign02")
public String testOpenFeign02(){
return myTestOpenFeign01.testOpenFeign02();
}
}
}
以上是简单的OpenFeign使用。一句话,@FeignClient注解把一个庞大的微服务抽象成了一个接口,@FeignClient(value = “xxxxx”)中的value 属性具体指定是哪个微服务。那么OpenFeign底层会帮我们通过微服务的服务名去获取到我们最关心的服务IP+Port。
但是光有IP+Port是不够的,我们需要定位到这个IP+Port旗下具体的资源路径。例如
192.168.22.50:8080/xxxx/xxxx。
那么这个资源路径就是通过接口中的方法脑袋上顶着的@GetMapping("/xxx/xxx")来表示
这个资源路径就和目标服务的资源路径一一对应!
2.简单了解一下OpenFeign以及负载均衡的实现原理
这个神奇的@FeignClient注解和@EnableFeignClients注解是怎么实现这样强大的远程调用功能的呢。
OpenFeign声明的接口,例如上面例子中的
@GetMapping("/testOpenFeign01")
String testOpenFeign01();
@GetMapping("/testOpenFeign02")
String testOpenFeign02();
都会在底层把这两个接口解析成方法元数据,再通过动态代理生成接口的代理,真正发请求的是代理类!
项目启动的时候,会用LoadBalancerFeignClient注册一个feign.Client到ioc容器中。
@Configuration
class DefaultFeignLoadBalancedConfiguration {
DefaultFeignLoadBalancedConfiguration() {
}
@Bean
@ConditionalOnMissingBean
public Client feignClient(CachingSpringLoadBalancerFactory cachingFactory, SpringClientFactory clientFactory) {
return new LoadBalancerFeignClient(new Default((SSLSocketFactory)null, (HostnameVerifier)null), cachingFactory, clientFactory);
}
}
FeignClientFactoryBean会生成一个@FeignClient注解的对应的service实例。
下面的源码我就不继续解读了,太麻烦。一句话总结一下吧!
一切都是由动态代理实现的,项目启动的时候由@FeignClient修饰的接口都会被生成一个代理实现类,负载均衡以及发送请求一系列操作都是在代理类中实现的!并且负载均衡策略默认使用的是Ribbon中的轮询机制。
那么怎么更改默认的这个负载均衡机制呢?很简单,和之前讲Ribbon那篇文章中的方式一样,看下面的代码
@Configuration
public class RibbonRules01 {
@Bean
public IRule rule01(){
return new RandomRule();
}
}
这样就定义了一个随机的负载均衡机制了。 因为在Feign的代理类中,它底层选择负载均衡算法的时候的逻辑是这样的:如果容器中没有负载均衡对象,那我就使用默认的轮询机制。现在我们往容器里注入了一个负载均衡对象,那我就用注入的这个。就是这么简单!
关于Feign的其他特性请看我的另一篇:SpringCloud中的OpenFeign的超时控制和日志增强。
好了 基本已经讲完,欢迎大家评论区指出不足,一起学习进步!
大家看完了点个赞,码字不容易啊。。。
相关文章
- 我在学习Nginx的时候认识的cookie和session,有什么不同?_征服bug
- 审核中台业务数据进审升级之路_Mo_mo???
- 将数据从Java Bean复制到另一个Java Bean_爱吃豆的土豆
- 二分查找算法的实现以及解决整数溢出问题_续写青春.
- 独家 | 如何利用ChatGPT自动完成6个数据科学领域的任务_数据派THU
- 抓住金三银四的尾巴,解锁程序员面试《刷题神器》_不吃西红柿丶
- sqlmap使用教程大全命令大全(图文)_Cwillchris
- MySQL 排序_不会写代码的菜_mysql 排序
- SQL查询数据以及排序_PGX_信_sql排序
- sql中 exists的用法_夙愿。_sql exists
- [carla入门教程]-5 使用ROS与carla通信_carla ros_一骑红尘荔枝来
- 【HTML5-小知识】块元素、行内元素和行内块元素_luckyboy!_行内块元素和行内元素
- Vue基本指令_须臾不敢忘
- 【SQLMap工具-1】SQLMap简介及简单应用实例_像风一样9
- Realsense d435i驱动安装、配置及校准_云端舞步
- 【ubuntu】ubuntu20.04安装ros noetic(亲测有效,附操作步骤)_米码收割机