OpenFeign
OpenFeign
OpenFeign是一个声明式的Http客户端- 官方地址: https://github.com/OpenFeign/feign其作用就是基于
SpringMvc相关注解,帮助我们优雅的实现Http请求的发送
快速入门
OpenFeign已经被SpringCloud自动装配,实现起来非常简单
引入依赖
包括OpenFeign依赖和负载均衡组件SpringCloudLoadBalancer依赖
<dependencies>
<!-- OpenFeign 依赖-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<!-- 负载均衡组件-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-loadbalancer</artifactId>
</dependency>
</dependencies>
在启动类中j加入@EnableFeignClients注解,开启OpenFeign功能
@MapperScan("com.hmall.cart.mapper")
@SpringBootApplication
@EnableFeignClients // 开启openfeign
public class CartApplication {
public static void main(String[] args) {
SpringApplication.run(CartApplication.class, args);
}
}
编写OpenFeign客户端
一般接口文件名为Client,具体服务的接口文件名为[服务名]Client
package com.hmall.cart.client;
import com.hmall.cart.domain.dto.ItemDTO;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import java.util.Collection;
import java.util.List;
//加入@FeignClient 注解 指定服务的名称
//声明 Feign 客户端:指定调用名为 "item-service" 的微服务
//指定目标服务:通过 value 或 name 属性指定要调用的微服务名称,在此例中 "item-service" 即为目标服务名
@FeignClient("item-service")
public interface ItemClient {
// 声明接口方法
@GetMapping("/items")
List<ItemDTO> queryItemsByIds(@RequestParam("ids") Collection<Long> ids);
}
使用
private void handleCartItems(List<CartVO> vos) {
//TODO 获取商品id
// 1.获取商品id
Set<Long> itemIds = vos.stream().map(CartVO::getItemId).collect(Collectors.toSet());
// 2.查询商品 使用openfeign
List<ItemDTO> items = itemClient.queryItemsByIds(itemIds);
if (CollUtils.isEmpty(items)) {
return;
}
}
连接池
定义
- 连接池是一种用于管理网络连接(如
HTTP连接、数据库连接等)的技术。 - 它的核心思想是预先创建并维护一组可重用的连接
- 而不是每次需要时都创建新的连接。
连接池的优势
- 性能提升:避免了频繁创建和销毁连接的开销
- 资源复用:已建立的连接可以被重复使用
- 减少延迟:重用现有连接比建立新连接要快得多
- 更好的资源管理:可以控制最大连接数,防止系统资源耗尽
工作原理
- 应用启动时,连接池初始化一定数量的连接
- 当应用需要发起请求时,从池中获取一个可用连接
- 当应用完成请求后,将连接放回池中,供下一次请求使用
- 如果池中没有可用连接且未达到最大连接数,则创建新连接
- 当连接池达到最大连接数,应用会等待,或者抛出异常
- 定期清理长时间未使用的空闲连
OpenFeign使用连接池
OpenFeign对Http请求做了优雅的伪装,不过其底层发起请求依赖其他框架。这些框架可以自己选择,包括
HttpURLConnection:默认实现,不支持连接池,每一次请求都会创建一个连接Apache HttpClient:支持连接池,请求速度比HttpURLConnection更快OkHttp:支持连接池
OpenFeign整合OKHttp连接池
引入依赖
<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-okhttp</artifactId>
</dependency>
开启连接池功能
feign:
okhttp:
enable: true # 开启连接池功能
最佳实践
OpenFeign`客户端的弊端
- 如果有多个服务,服务间需要相互调用,那么每个服务都需要编写一个
OpenFeign客户端,造成大量的重复代码 - 如果服务变动,那么需要修改多个客户端
- 如果服务调用失败,那么需要逐层去寻找失败的原因
统一API管理
- 为了解决重复代码和维护困难的问题,可以将所有服务的
Feign客户端接口抽取到一个公共模块中, - 各个服务引用该公共模块,避免重复编写相同的客户端代码。
注意
- 将公共模块的
OpenFeign客户端和客户端需要用到的DOT抽离到单独的模块中后 - 需要在启动类中配置
OpenFeign客户端的开关指定OpenFeign的扫描包
@SpringBootApplication
@EnableFeignClients(basePackages = "com.hmall.api.client")// 指定扫描包
public class ApiApplication {
}
日志输出
openfeign默认情况下,不会输出任何日志,它只会在FeignClient客户端所在包的日志级别为DEBUG时才会输出日志,而且它的日志级别有4级
NONE: 不输出日志,这是默认值BASIC: 仅记录请求方法、URL、响应状态码和执行时间HEADERS: 记录BASIC级别的信息,并记录请求和响应的请求头FULL: 记录HEADERS级别的信息,并记录请求和响应的正文和元数据
自定义日志级别
局部配置
openfeign自定义日志级别需要声明一个类型为Logger.Level的bean,在其中定义日志级别package com.heima.api.config; @Bean public Logger.Level feignLoggerLevel() { return Logger.Level.FULL; }在客户端注解
@FeignClient中指定日志级别
package com.heima.api.client;
@FeignClient(name = "item-service", configuration = feignLoggerLevel.class)
public interface ItemClient {
@GetMapping("/items")
List<ItemDTO> queryItemsByIds(@RequestParam("ids") Collection<Long> ids);
}
全局配置
如果想要全局配置,可以在启动类的@EnableFeignClients开关注解中添加defaultConfiguration默认日志级别属性
在公共的客户端模块中定义bean对象,并将方法的返回值交给ioc容器管理
package com.hmall.api.config;
import feign.Logger;
import org.springframework.context.annotation.Bean;
public class DefaultFeginConfig {
@Bean //将此方法的返回值作为bean加入到spring容器中
public Logger.Level feignLoggerLevel() {
return Logger.Level.FULL;
}
}
在启动类中添加@EnableFeignClients注解,并指定默认的日志级别属性defaultConfiguration
package com.hmall.cart;
import com.hmall.api.config.DefaultFeginConfig;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.openfeign.EnableFeignClients;
@MapperScan("com.hmall.cart.mapper")
@SpringBootApplication
@EnableFeignClients(basePackages = "com.hmall.api.client", defaultConfiguration = DefaultFeginConfig.class)
// 开启openfeign 配置扫描包
public class CartApplication {
public static void main(String[] args) {
SpringApplication.run(CartApplication.class, args);
}
}