SpringCloud中的OpenFeign以及与Feign的区别

2022-08-07 13:17:41

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组件publicclassDeptConsumer_80{publicstaticvoidmain(String[] args){
        SpringApplication.run(DeptConsumer_80.class, args);}}
						这里是消费端的代码!
定义一个接口 用@FeignClient修饰,@FeignClient注解的value属性值
填写当前我这个接口对应的哪个微服务,也就是微服务在注册中心中的名称。
可以理解为这一个接口就对应一个微服务了。
那这个接口中对应的方法是什么呢?可以他妈的乱定义吗?
不行,方法必须对应消费端的Controller层的暴露出来的接口以及URL地址。@Component@FeignClient(value="SPRINGCLOUD-PROVIDER-DEPT")publicinterfaceMyTestOpenFeign01{@GetMapping("/testOpenFeign01")
     StringtestOpenFeign01();@GetMapping("/testOpenFeign02")
     StringtestOpenFeign02();}

						这里是服务端的代码!
	这是服务端暴露出来的两个接口 URL分别是/testOpenFeign01,/testOpenFeign02。
	如果我们在上面的消费端Feign接口中想调用到这两个接口,那上面的MyTestOpenFeign01 接口中
	的两个方法也必须打上@GetMapping注解,Url也要一一对应!@RestControllerpublicclassDeptController{@Autowiredprivate DeptService deptService;@GetMapping("/testOpenFeign01")public StringtestOpenFeign01(){return deptService.testOpenFeign01();}@GetMapping("/testOpenFeign02")public StringtestOpenFeign02(){return deptService.testOpenFeign02();}
	最后是消费端的Controller层,我们把我们刚刚定义的MyTestOpenFeign01注入进来
	调用接口中的方法,他就会自动的默认的以负载均衡的方式远程调用到了服务端的"/testOpenFeign01""/testOpenFeign02"接口@RestControllerpublicclassOpenFeignController{@Autowiredprivate MyTestOpenFeign01 myTestOpenFeign01;@RequestMapping("/consumer/testOpenFeign01")public StringtestOpenFeign01(){return  myTestOpenFeign01.testOpenFeign01();}@RequestMapping("/consumer/testOpenFeign02")public StringtestOpenFeign02(){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容器中。

@ConfigurationclassDefaultFeignLoadBalancedConfiguration{DefaultFeignLoadBalancedConfiguration(){}@Bean@ConditionalOnMissingBeanpublic ClientfeignClient(CachingSpringLoadBalancerFactory cachingFactory, SpringClientFactory clientFactory){returnnewLoadBalancerFeignClient(newDefault((SSLSocketFactory)null,(HostnameVerifier)null), cachingFactory, clientFactory);}}

FeignClientFactoryBean会生成一个@FeignClient注解的对应的service实例。
下面的源码我就不继续解读了,太麻烦。一句话总结一下吧!

一切都是由动态代理实现的,项目启动的时候由@FeignClient修饰的接口都会被生成一个代理实现类,负载均衡以及发送请求一系列操作都是在代理类中实现的!并且负载均衡策略默认使用的是Ribbon中的轮询机制。

那么怎么更改默认的这个负载均衡机制呢?很简单,和之前讲Ribbon那篇文章中的方式一样,看下面的代码

@ConfigurationpublicclassRibbonRules01{@Beanpublic IRulerule01(){returnnewRandomRule();}}

这样就定义了一个随机的负载均衡机制了。 因为在Feign的代理类中,它底层选择负载均衡算法的时候的逻辑是这样的:如果容器中没有负载均衡对象,那我就使用默认的轮询机制。现在我们往容器里注入了一个负载均衡对象,那我就用注入的这个。就是这么简单!

关于Feign的其他特性请看我的另一篇:SpringCloud中的OpenFeign的超时控制和日志增强

好了 基本已经讲完,欢迎大家评论区指出不足,一起学习进步!

大家看完了点个赞,码字不容易啊。。。

  • 作者:易柏州Innovation
  • 原文链接:https://blog.csdn.net/J169YBZ/article/details/117910861
    更新时间:2022-08-07 13:17:41