HTTP客户端Feign
之前RestTemplate发起远程调用的代码:
缺点:
- 代码可读性差
- 参数复杂URL难维护
Feign的介绍和基本使用
Feign是一个声明式的http客户端,用Feign来代替了RestTemplate
使用Feign的步骤:
-
引入依赖
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-openfeign</artifactId> </dependency>
-
在order-service的启动类中添加@EnableFeignClients注解开启Feign功能
@EnableFeignClients @MapperScan("cn.itcast.order.mapper") @SpringBootApplication public class OrderApplication { public static void main(String[] args) { SpringApplication.run(OrderApplication.class, args); } }
-
编写Feign客户端:
@FeignClient("userservice") public interface UserClient{ @GetMapping("/user/{id}") User findById(@PathVariable("id") Long id); }
主要是基于SpringMVC的注解来声明远程调用的信息,比如
- 服务名称:userservice
- 请求方式:GET
- 请求路径:/user/{id}
- 请求参数:Long id
- 返回值类型:User
更改orderservice
public Order queryOrderById(Long orderId) {
// 1.查询订单
Order order = orderMapper.findById(orderId);
// 2.用Feign远程调用
User user = userClient.findById(order.getUserId());
// 3.封装user到order
order.setUser(user);
// 4.返回
return order;
}
Feign中已经集成Ribbon实现了负载均衡
Feign的自定义配置
Feign运行自定义配置来覆盖默认配置,可修改的配置如下
修改Feign配置文件的两种方式:
-
配置文件方式:
-
全局生效
feign: client: config: default: #这里用default就是全局配置,如果是写服务名称就是针对某个微服务 loggerlevel: FULL #日志级别
-
局部生效
feign: client: config: userservice: #这里用default就是全局配置,如果是写服务名称就是针对某个微服务 loggerlevel: FULL #日志级别
-
-
java代码方式,需要先声明一个bean:
public class FeignClientConfiguration{ @Bean public Logger.Level.feignLogLevel(){ return Logger.Level.BASIC; } }
如果是全局配置使用注解
@MapperScan("cn.itcast.order.mapper") @SpringBootApplication @EnableFeignClients(defaultConfiguration = DefaultFeignConfiguration.class) public class OrderApplication { public static void main(String[] args) { SpringApplication.run(OrderApplication.class, args); } }
如果是局部配置
@FeignClient(value = "userservice",configuration = FeignClientConfiguration.calss) public interface UserClient { @GetMapping("/user/{id}") User findById(@PathVariable("id") Long id); }
小结
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-daC73BYW-1670245216926)(C:\Users\Lenovo\AppData\Roaming\Typora\typora-user-images\image-20221205180830142.png)]
Feign的性能优化
Feign底层客户端实现:
- URLConnection:默认实现,不支持连接池
- Apache HttpClient:支持连接池
- OKHttp:支持连接池
因此优化Feign的性能主要包括:
- 使用连接池代替默认的URLConnection
- 日志级别,最好用basic或者none
Feign添加HttpClient的支持:
<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-httpclient</artifactId>
</dependency>
配置连接池:
feign:
client:
config:
default:
loggerLevel: FULL
httpclient:
enabled: true #开启feign对HttpClient的支持
max-connections: 200 #最大连接数
max-connections-per-route: 50 #每个路径的最大连接数
Feign的最佳实践分析
方法一(继承):给消费者的FeignClient和提供者的controller定义统一的父类作为标准。
不推荐:会造成紧耦合
方法二(抽取):将FeignClient抽取为独立模块,并且把接口有关的POJO、默认的Feign配置放到这个模块中,提供给所有的消费者。
创建一个feign-api的项目抽取其他项目中的重复模块:UserClient、User、DefaultConfig等做成 jar包导入依赖
问题:虽然耦合度较松,但是因为需要导入jar包中所有的东西,更占内存
实现Feign的最佳实践
实现最佳实践方式二:
-
创建一个module,命名为feign-api,然后引入feign的starter依赖
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-openfeign</artifactId> </dependency> </dependencies>
-
将order-service中编写的UserClient、User、DefaultFeignConfiguration都复制到feign-api项目中
-
在order-service中引入feign-api的依赖
<!--引入feign的统一api--> <dependency> <groupId>cn.itcast.demo</groupId> <artifactId>feign-api</artifactId> <version>1.0</version> </dependency>
-
修改order-service中的所有与上述三个组件有关的import部分,改成导入feign-api中的包
重新启动order-service时会出现问题:'cn.itcast.feign.clients.UserClient' that could not be found.
原因:order-service默认访问的包是启动类所在的包,重新建立一个feign-api的以后,启动类无法扫描到userClient
解决方法:
方法一:指定FeignClient所在包
@EnableFeignClients(bassPackage = "cn.itcast.feign.client")
方法二:指定FeignClient字节码
@EnableFeignClients(clients={UserClient.class})
推荐
-
重启测试