Feign 声明式服务调用
一、feign介绍
1、什么是feign?
feign是spring cloud提供的声明式的http客户端,工作在consumer端
feign支持springmvc注解
feign集成了Ribbon也支持负载均衡
(ribbon+restTemplate)+优化=feign
2、feign的启动器
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
二、Feign的入门案例
1、创建provicer模块
provicer测试controller
@RestController
@RequestMapping("/provider")
public class ProviderController {
@Autowired
private UserService userService;
//restful风格传参
@RequestMapping("/getUserById/{id}")
public User getUserById(@PathVariable Integer id){
return userService.getUserById(id);
}
//拼接传参
@RequestMapping("/getUserById")
public User getUserByIdRequestParam(@RequestParam("id") Integer id){
return userService.getUserById(id);
}
//接收对象
@RequestMapping("/getUser")
public User getUser(@RequestBody User user) {
return userService.getUser(user);
}
}
provicer测试UserService接口类
public interface UserService {
User getUserById(Integer id);
User getUserByIdRequestParam(Integer id);
User getUser(User user);
}
provicer测试UserServiceImpl实现类
@Service
public class UserServiceImpl implements UserService {
@Override
public User getUserById(@RequestParam("id") Integer id) {
return new User(id,"zs",22);
}
@Override
public User getUserByIdRequestParam(Integer id) {
return new User(id,"zs",22);
}
@Override
public User getUser(User user){
return user;
}
}
启动类
@SpringBootApplication
@EnableDiscoveryClient//向注册中心注册该服务,并可以获取其他服务的调用地址
public class FeignProviderApp {
public static void main(String[] args) {
SpringApplication.run(FeignProviderApp.class,args);
}
}
appliction.yml 配置文件
spring:
cloud:
nacos:
discovery:
server-addr: 192.168.112.130:8848 #nacos服务的地址
application:
name: feign-provider #向注册中心注册的名字
server:
port: 9090
创建 feign接口模块
feign接口类
@FeignClient("feign-provider")
@RequestMapping("/provider")
public interface UserFeign {
@RequestMapping("/getUserById/{id}")
User getUserById(@PathVariable("id") Integer id);
@RequestMapping("/getUser")
User getUser(@RequestBody User user);
}
feign的pom.xml文件
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>springbootCloud-parent</artifactId>
<groupId>com.alibaba</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>feign_interface</artifactId>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
<dependencies>
<!--nacos客户端-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<!--Spring Cloud OpenFeign Starter -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<dependency>
<groupId>com.bjpowernode</groupId>
<artifactId>common</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<!-- http连接池-->
<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-httpclient</artifactId>
</dependency>
</dependencies>
</project>
创建consumer模块
consumer测试Usercontroller类
@RestController
@RequestMapping(value = "/consumer")
public class ConsumerController {
@Autowired
private UserFeign userFeign;
@RequestMapping(value="/getUserById/{id}")
public User getUserById(@PathVariable Integer id){
return userFeign.getUserById(id);
}
@RequestMapping(value="/getUserById")
public User getUserByIdRequestParam(@RequestParam("id") Integer id){
return userFeign.getUserById(id);
}
@RequestMapping(value="/getUser")
public User getUserById(@RequestBody User user){
return userFeign.getUser(user);
}
}
启动类
@SpringBootApplication
@EnableDiscoveryClient //启动feign客户端
@EnableFeignClients //feign扫描它自己的注解
public class FeignConsumerApp {
public static void main(String[] args) {
SpringApplication.run(FeignConsumerApp.class,args);
}
}
application.yml 配置文件
spring:
cloud:
nacos:
discovery:
server-addr: 192.168.112.130:8848 #nacos服务的地址
application:
name: feign-consumer #向注册中心注册的名字
server:
port: 80
compression:
enabled: true #开启gzip压缩
#feign优化日志配置
feign:
client:
config:
default:
loggerLevel: full
#设置全局日志输出登记为debug级别配合feign日志输出
logging:
level:
com.bjpowernode.feign: debug
#feign对于超时的优化
ribbon:
ConnectTimeout: 5000 #请求连接的超时时间
ReadTimeout: 5000 #请求处理的超时时间
@EnableFeignClients 单独领出来说一下这个注解:一张图即可看懂
feign的传参方式
有上面的入门案例consumer测试Usercontroller类中可以看出三种传参方式,也是最常用的传参方式
-
restful 传参:
使用@PathVariable 注解接收路径中的参数。在feign接口类中注意,此时的@PathVariable 与
consumer测试Usercontroller类 中的 @PathVariable 的作用完全不同,因为没有直接的Template的参与,路径
需要feign自己进行路径拼接,所以此时的@Pathvariable 注解是为了给feign自己指明拼接方式。 -
路径拼接传参:
使用@RequestParam 注解指明拼接方式 -
对象传参:
使用 @RequestBody 注解指明拼接方式,
注意:此时的对象传参是按照Json形式传参
此时小伙伴指定满头的问号?这什么东西就这就能远程调用了?
接下来刚给大家看一下我自己理解的feign远程调用原理
feign的原理
- 在未产生调用前,feign 首先进行指定包下的注解检索,如图
- 通过实现远程调用的只有一个feign的接口,所以大概率使用的是类似Mybatis的代理方式,果不其然:
- 代理类通过SynchronousMethodHandler.invoke()进行远程调用
- 代理类会通过RequestTemplate创建Request,并且发送请求
主要就这了,不明白的小伙伴自己写个Demo测试跑跑看就明白了。
feign的优化
众所周知http协议三次握手四次挥手都比较慢,为什么还要用基于http协议的feign呢?为什么不用dubbo呢?
-
从协议上来讲:
Feign更加优雅简单,Feign通过REST API实现的远程调用,基于http协议,服务提供者可以直接对外暴露接口,
供服务消费者直接调用。
Dubbo是通过RPC实现的远程调用,支持多种传输协议,可以在更多的场景选择最适合的传输协议。 -
负载均衡来讲:
Feign默认使用了Ribbon作为负载均衡组件,使用方便
Dubbo也同样支持负载均衡,但是支持的组件更加灵活 -
当然还可以从通信性能,容错机制等等其他方面来对比feign这里就不再啰嗦,如果有想要研究的小伙伴可以自行百度,
结果就是各有千秋,看小伙伴想学哪一种了。推荐使用feign,原因嘛就是毕竟全家桶。
- 日志优化
此优化主要是为了更清晰的看到传参内容,以及请求头,请求体,请求路径,请求方法和响应头,响应体等等内容效果图如下:
2. 超时优化
此优化是为了处理feign连接超时的问题,毕竟http协议,当高并发的情况下很有可能会出现
这个异常,所以还是需要配置一下的
-
连接池优化
此优化为了提高feign的工作效率
-
gzip压缩优化
无所多言,gzip 真香
优化方式在consumer模块的application.yml 配置文件中,有需要的小伙伴可以自行CV,
注意超时和日志优化有的编辑器是不会提示的哦,