目录
一, RestTemplate远程调用存在的问题
二, Feign的远程调用
2.1 什么是Fegin
2.2 Feign的使用(代替RestTemplate)
1. 引入依赖
2. 添加注解
3. 编写Feign的客户端
4. 测试
5. 总结
2.3 自定义配置
1. 配置文件方式
2. Java代码方式
三, Feign使用优化
3.1 使用连接池
1. 引入依赖
2. 配置连接池
3. 总结
3.2 抽取Feign的Client模块进一步优化
1. 抽取
2. 在order-service中使用feign-api
3. 重启测试
4. 解决扫描包问题
SpringCloud(一) 服务架构的演变及注册RestTemplate实现服务的远程调用-CSDN博客
在这篇博客中我们学会了如何使用RestTemplate实现微服务之间的远程调用,我们来看一下利用RestTemplate发起远程调用的代码:
这种方式存在以下的问题:
所以引入了Feign帮我们解决上述问题,使得远程调用的代码更加优雅.
Fegin是一个声明式的http客户端,官方地址:https://github.com/OpenFeign/feign
其作用就是帮助我们优雅的实现http请求的发送,解决RestTemplate中提到的问题.
在order-service服务的pom文件中引入feign的依赖
org.springframework.cloud
spring-cloud-starter-openfeign
在order-service的启动类添加注解开启Feign的功能
在order-service新建一个接口,内容如下:
package cn.itcast.order.client;
import cn.itcast.order.pojo.User;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
@FeignClient("userservice")
public interface UserClient {
@GetMapping("/user/{id}")
User findById(@PathVariable("id") Long id);
}
这个客户端是基于SpringMVC的注解来声明远程调用的信息,比如:
这样,Feign就可以帮助我们发送http请求,无需自己使用RestTemplate来发送了.
修改order-service的OrderController类中的queryOrderById方法,使用Feign客户端代替RestTemplate:
使用Feign的步骤:
Feign支持很多的自定义配置,如下表所示:
类型 | 作用 | 说明 |
feign.Logger.Leve | 修改日志级别 | 包含四种不同的级别:NONE、BASIC、HEADERS、FULL |
feign.codec.Decoder | 响应结果的解析器 | http远程调用的结果做解析,例如解析json字符串为java对象 |
feign.codec.Encoder | 请求参数编码 | 将请求参数编码,便于通过http请求发送 |
feign. Contract | 支持的注解格式 | 默认是SpringMVC的注解 |
feign. Retryer | 失败重试机制 | 请求失败的重试机制,默认是没有,不过会使用Ribbon的重试 |
一般情况下,默认值就能满足我们使用,如果要自定义时,只需要创建自定义的@Bean覆盖默认Bean即可,下面以日志为例来演示如何自定义配置.
基于配置文件修改Feign的日志级别可以针对单个服务:
feign:
client:
config:
userservice: # 针对某个微服务的配置
loggerLevel: FULL # 日志级别
也可以针对所有服务:
feign:
client:
config:
default: # 针对某个微服务的配置
loggerLevel: FULL # 日志级别
而日志的级别分为四种:
以BASIC为例:
先修改配置文件
重新访问查看日志信息
也可以基于Java代码来修改日志级别,先声明一个类,然后声明一个Logger.Level对象:
public class DefaultFeignConfiguration {
@Bean
public Logger.Level feignLogLevel(){
return Logger.Level.BASIC; // 日志级别为BASIC
}
}
如果要全局生效,将其放到启动类的@EnableFeignClients这个注解中:
@EnableFeignClients(defaultConfiguration = DefaultFeignConfiguration .class)
如果是局部生效,则把它方到对应的@FeignClient这个注解中:
@FeignClient(value = "userservice", configuration = DefaultFeignConfiguration .class)
Feign底层发起http请求,依赖于其他的框架,其底层客户端实现包括:
因此,提高Feign的性能主要手段就是使用连接池代替默认的URLConnection
这里我们用Apache HttpClient来演示:
在order-service的pom文件中引入Apache的HttpClient依赖:
io.github.openfeign
feign-httpclient
在order-service的application.yml中添加配置:
feign:
client:
config:
default: # default全局的配置
loggerLevel: BASIC # 日志级别,BASIC就是基本的请求和响应信息
httpclient:
enabled: true # 开启feign对HttpClient的支持
max-connections: 200 # 最大的连接数
max-connections-per-route: 50 # 每个路径的最大连接数
此时,启动order-service服务,其底层就是使用的Apache的HttpClient了.
Feign的优化:
通过代码我们可以发现,Feign的客户端与服务提供者的controller代码非常相似:
有没有一种办法简化这种重复的代码编写呢?
答案是肯定的;可以将Feign的Client抽取为独立模块,并且把接口有关的POJO,默认的Feign配置都放到这个模块中,提供给所有消费者使用;例如:将UserClient,User,Feign的默认配置都抽取到一个feign-api包中,所有微服务引入该依赖包,即可直接使用.
首先创建一个module,命名为feign-api:
项目结构:
在feign-api中然后引入feign的starter依赖
org.springframework.cloud
spring-cloud-starter-openfeign
然后,order-service中编写的UserClient,User,DefaultFeignConfiguration都复制到feign-api项目中
首先,删除order-service中的UserClient,User,DefaultFeignConfiguration等类或接口;
在order-service的pom文件中中引入feign-api的依赖:
cn.itcast.demo
feign-api
1.0
修改order-service中的所有与上述三个组件有关的导包部分,改成导入feign-api中的包
重启之后发现服务报错了:
这是因为UserController现在在cn.itcast.feign.clients包下,而order-service的@EnableFeignClient注解是在cn.itcast.order包下,不在同一个包,无法扫描到UserClient.
方式一:
指定Feign应该扫描的包:
@EnableFeignClients(basePackages = "cn.itcast.feign.clients")
方式二:
指定需要加载的Client接口(使用的更多):
@EnableFeignClients(clients = {UserClient.class})