【Spring Cloud Alibaba】(二)微服务调用组件Feign原理+实战
系列目录
【Spring Cloud Alibaba】(一)微服务介绍 及 Nacos注册中心实战
本文目录
- 系列目录
- 前言
- 什么是RPC?
- Feign和OpenFeign都是什么?
- HTTP调用 vs Feign(RPC)调用
- 单独使用Feign实战
- Feign核心源码解读
- Feign整体设计架构
- Spring Cloud OpenFeign实战
- Feign在实际项目的通常做法
- 最后
前言
通过上文,我们掌握了Spring Cloud Alibaba微服务框架的初始环境搭建,并能通过Nacos
注册中心的服务注册和发现,配合RestTemplate和Ribbon
,实现2个服务之间通过服务名
进行远程调用。
实际上,微服务之间的调用还有更简单、更方便、更强大的调用方式,那就是RPC调用
!本文所讲的微服务调用组件Feign,正是RPC框架之一!
本文会循序渐进的从Feign讲到OpenFeign,并会讲到Feign核心原理和实际项目使用OpenFeign的通常做法:
- 单独使用Feign实战,实现2个服务之间的RPC调用;
- Feign核心源码解读;
- Feign整体设计架构预览;
- Spring Cloud Alibaba快速整合Feign,实现2个服务之间通过Nacos服务注册发现的RPC调用;
- Feign在实际项目的通常做法。
什么是RPC?
RPC(Remote Produce Call)
,即远程过程调用,目的是:调用[远程服务方法]像调用[本地方法]一样
!
Feign和OpenFeign都是什么?
Feign
是RPC框架中的一种,是Netflix开发的声明式、模板化的HTTP客户端,底层依然是走的HTTP调用,但表现形式是接口调用,可以帮助我们更加便捷、优雅地调用HTTP API,就像调用本地方法一样方便。
它通过扩展集成了Netflix Ribbon,从而拥有负载均衡的功能,默认是基于配置来提供服务实例列表。
OpenFeign
是指Spring Cloud OpenFeign,是Spring Cloud开发的,对Feign进行了增强,使其支持Spring MVC注解,还整合了Spring Cloud Netflix Ribbon,从注册中心获取服务实例(在Spring Cloud Alibaba框架中的注册中心默认是Nacos),从而使得Feign与Spring Cloud整合。
HTTP调用 vs Feign(RPC)调用
回顾一下RestTemplate
方式的服务调用(gg-user
是服务名):
@Autowired
private RestTemplate restTemplate;@GetMapping("/getUserName")
public String getUserName(@RequestParam("id") Integer id) {String url = String.format("http://%s/user?id=%s", "gg-user", id);return restTemplate.exchange(url, HttpMethod.GET, null, String.class).getBody();
}
换成Feign
调用,感受一下效果:
@Autowired
private UserService userService;@GetMapping("/getUserName")
public String getUserName(@RequestParam("id") Integer id) {return userService.getUserName(id);
}
What? Feign这个是远程调用?
对,这就是远程调用,丝毫看不出来,和调用本地方法一样的湿滑!
怎么实现的?如果你用过Mybatis,可以往Mybatis接口的实现类上思考,也许你能想到答案!
单独使用Feign实战
那么接下来,我们一起看一下,如果不在Spring Cloud框架下,Feign如何实现RPC调用!
本次实战案例的调用方:普通的SpringBoot程序。
调用地址:http://gg-user/user?id=123
gg-user
是被调用的服务名
- 1、引入Feign依赖
<!-- Feign核心 -->
<dependency><groupId>io.github.openfeign</groupId><artifactId>feign-core</artifactId><version>10.12</version>
</dependency>
<!-- Feign集成Netflix Ribbon -->
<dependency><groupId>io.github.openfeign</groupId><artifactId>feign-ribbon</artifactId><version>10.12</version>
</dependency>
- 2、定义接口UserService
import feign.Param;
import feign.RequestLine;public interface UserService {@RequestLine("GET /user?id={id}")String getUserName(@Param("id") Integer id);
}
虽然不是SpringMVC的注解,但从
@RequestLine
注解能看出这是一个GET请求
,路径是/user?id={id}
,{id}是占位符,通过@Param("id")
注解获取实际传入的id值。
- 3、为UserService接口生成实现类
这里通过JavaConfig配置@Bean的方式实现注入:
@Configuration
public class FeignConfig {@Beanpublic UserService userService() {return Feign.builder().client(RibbonClient.create()).target(UserService.class, "http://gg-user");}
}
- 4、配置Ribbon的服务实例
这里配置到application.properties,因为不在Spring Cloud环境,所以没有注册中心,需要从配置文件中获取服务实例。
gg-user.ribbon.listOfServers=localhost:8081,localhost:8082
调用代码:
@Autowired
private UserService userService;@GetMapping("/getUserName")
public String getUserName(@RequestParam("id") Integer id) {return userService.getUserName(id);
}
这样我们通过Feign就实现了非常优雅的RPC调用,最终GET请求url可能是:
http://localhost:8081/user?id=123
http://localhost:8082/user?id=123
Feign核心源码解读
Feign的核心代码写的非常好,非常值得我们学习和借鉴,所以我推荐大家学习下源码,本文只解读两个核心点作为抛转引玉。
Feign是如何动态生成的实现类?
return Feign.builder().client(RibbonClient.create()).target(UserService.class, "http://gg-user");
通过这段代码,可以看出是通过target泛型方法
生成的UserService实现类。
target
会先build()出Feign的实现类ReflectiveFeign, 再调用ReflectiveFeign.newInstance方法,如下图:
ReflectiveFeign.newInstance方法内会调用Proxy.newProxyInstance生成动态代理类,如下图:
Feign是如何集成的Ribbon?
对于JDK动态代理,会在InvocationHandler里最终发起HTTP请求。而Feign把HTTP请求这部分做到了动态可插拔,封装成了Client接口
,可以支持JDK 原生的 URLConnection、Apache HttpClient、OkHttp等等各类Client的实现。上面builder().client
方法,就是用来指定Client的实现类。
这里指定的Client是:RibbonClient,它并不是HTTP调用的直接实现,从名子可以看出它主要整合Ribbon提供的是负载均衡功能。从实现上来看,它使用的是装饰器设计模式,就是为了在提供负载均衡功能的同时,还可以灵活指定其它Client,从而达到动态扩展的目的。
Feign整体设计架构
通过上面的源码解读,我想你应该可以看懂架构图的上部和下部,Feign实际在设计上考虑了很多扩展功能,像Client、Log、Interceptor、Contract等等,非常灵活,非常强大,给了我们足够的扩展空间,它对所有的组件都提供了接口,如果对接口的实现类不满意,还可以基于Feign的接口来自定义实现。
所以,Spring Cloud正是通过Feign的扩展,将Feign完美整合到Spring Cloud框架中,形成了Spring Cloud OpenFeign。
Spring Cloud OpenFeign实战
单独使用Feign的时候,我们还需要做一些配置,可一旦被Spring Cloud整合,那么一切就会变得非常非常简单,只需要加依赖
+加注解
!
接下来,基于上文的Spring Cloud Alibaba工程环境,我们改造demo-a
服务,将RestTemplate调用改成OpenFeign调用。
只需要三步就可以达到效果。
- 第一步:引入 OpenFeign 组件
额外增加包spring-cloud-starter-openfeign
,不用加版本,都在父工程定义了,上文已经说了版本。
<!-- Spring Cloud Open Feign -->
<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<!-- Spring Cloud Nacos Service Discovery 这是支持Nacos时加过的-->
<dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
- 第二步:定义远程API接口加@FeignClient
接口上额外增加@FeignClient
注解,value=服务名
方法上换成SpringMVC注解
,代替Feign注解
@FeignClient(value = "demo-b")
public interface UserService {@GetMapping("/user?id={id}")String getUserName(@RequestParam("id") Integer id);
}
- 第三步:启动类加@EnableFeignClients
启动类上再增加注解@EnableFeignClients
,用于扫描@FeignClient
并生成动态代理类等
注意:如果UserService接口与启动类不在一个包package下,可以通过
basePackages
指定@FeignClient
所在包路径.
@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients
public class DemoARunner {public static void main(String[] args) {SpringApplication.run(DemoARunner.class, args);}
}
通过以上三步操作,我们就达到了调用[远程服务方法]像调用[本地方法]一样!
调用代码如下:
@Autowired
private UserService userService;@GetMapping("/getUserName")
public String getUserName(@RequestParam("id") Integer id) {return userService.getUserName(id);
}
Feign在实际项目的通常做法
在实际的Spring Cloud项目中,接口定义往往不是消费方来定义,通常做法是:
服务提供方
负责定义、发布接口包,供消费方
使用。
- 好处:
- 一个服务可能被多个服务调用,可以避免每个消费方都定义接口
- 服务提供方最清楚接口如何调用
- 对于消费方:
- 引入接口Jar包
- 增加@EnableFeignClients注解保证能扫描到Jar包
这样,消费方就可以很方便的直接调用了,你get了吗?
最后
通过本文,我们掌握了Feign的基本使用、核心原理,以及Spring Cloud Alibaba如何快速整合Feign,真的太简单了!你是不是觉得这样就够了?但在实际项目使用OpenFeign时,我们常常会遇到各种需求,需要用到它提供的扩展,例如日志分析、自定义统一拦截器、客户端组件配置、GZIP压缩等等,这也是我计划将在下文分享的内容,如果感觉不错,欢迎订阅本专栏,后面还有更多的【Spring Cloud Alibaba】实战知识陆续放出。
关注我 天罡gg 分享更多干货: https://blog.csdn.net/scm_2008 文章目录 业务场景 实现 自定义拦截器 暴漏接口 服务实现 服务调用者 验证 源码 业务场景 服务A 获取到Token值后,要传递给 服务B进行校验 . 在微服务架构下如何实现呢? 实现 自定义拦截器 ... 作者介绍 程序员十三,多年一线开发经验,历任高级开发工程师.后端主程.技术部门主管等职位.同时也是开源项目的爱好者和贡献者.掘金优秀作者.CSDN 博客专家.实体图书作者.专栏作者.视频讲师. 小册介 ... 作者 | 童子龙 掌门教育基础架构部架构师 **导读:**本文整理自作者于 2020 年云原生微服务大会上的分享<掌门教育云原生落地实践>,本文主要介绍了掌门教育云原生落地实践,主要围绕 ... 本篇是「跟我学 Spring Cloud Alibaba」系列的第一篇, 每期文章会在公众号「架构进化论」进行首发更新,欢迎关注. 1.Spring Cloud Alibaba 是什么 Spring ... 文章目录 一.JAVA 项目中如何实现远程接口调用? 二.什么是Feign 2.2 Feign的优势 2.2 Feign的设计架构与底层原理源码 2.3 Ribbon&Feign对比 Ribb ... <?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://mave ... 关注DD,除了前沿消息,还有每周福利哦 Spring Cloud Alibaba致力于提供微服务开发的一站式解决方案,它是Spring Cloud组件被植入Alibaba元素之后的产物. 利用Spri ... 注意:用手机查看排版可能不太友好, 1. 简介 在<Spring Cloud Alibaba 服务注册与发现>篇中曾提到,Spring Cloud Alibaba Nacos Discov ... 1. 简介 在<Spring Cloud Alibaba 服务注册与发现>篇中曾提到,Spring Cloud Alibaba Nacos Discovery 能无缝整合 Spring C ...
大家的「关注❤️ + 点赞
【Spring Cloud Alibaba】(二)微服务调用组件Feign原理+实战相关推荐
最新文章
热门文章