5.1 Feign介绍
Feign是一个HTTP客户端,为了使服务消费者更加方便、优雅的调用服务提供者。就想调用本地service一样简单,使用者完全感觉不到实在远程http调用服务。
Feign特性:
-
Spring MVC注解
-
整合了Ribbon负载均衡组件,实现调用服务实例的负载均衡
-
支持HTTP请求和响应的压缩
5.2 Feign基本使用
主要流程是:
1.在服务消费端添加open-feign依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
2.在服务消费端启动类标记@EnableFeignClients注解
@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients
public class BusinessApplication {
public static void main(String[] args) {
SpringApplication.run(BusinessApplication.class, args);
}
}
标记此注解的目的是扫描所有带@FeignClient注解的类
3.在服务消费端编写Feign客户端接口
/**
* @description: 定义一个Feign接口,用于调用device服务
* @author:xg
* @date: 2024/12/13
* @Copyright:
*/
@FeignClient("smart-device")
public interface FeignDeviceService {
@GetMapping("/device/hello")
String hello(@RequestParam("param") String param);
}
在服务提供端的device服务接口
@RestController
@RequestMapping("/device")
public class DeviceController {
@GetMapping("/hello")
public String hello(@RequestParam("param") String param, HttpServletRequest request) {
return "hello: " + param + " 服务实例端口:" + request.getServerPort();// 当前实例端口号
}
}
4.在服务消费端编写接口调用Feign客户端接口
@RestController
@RequestMapping("/deviceData")
@Slf4j
public class DeviceDataController {
@Resource
private FeignDeviceService feignDeviceService;
@GetMapping("/hello")
public String hello(@RequestParam("param") String param) {
return feignDeviceService.hello(param);
}
}
这些流程在前面Nacos注册中心章节,有说明。
5.3 Feign的运行原理
- 启动类添加@EnableFeignClients注解,会扫描添加了@FeignClient注解的Feign接口类
- Feign接口类注入IoC容器,Feign接口类的方法被调用时,通过JDK代理的方式生产RequestTemplate对象,此对象封装了Http请求的参数、请求方法等信息
- 由RequestTemplate生成Request对象,然后交给client处理,这个client可以时JDK原生的URLConnection、HttpClient、Okhttp。client会封装到LoadBalanceClient中,结合Ribbon负载均衡调用服务实例
5.4 Feign的各种配置
5.4.1 Feign开启GZIP压缩
Feign对请求和响应开启GZIP压缩,可以提高通信效率。
feign:
compression:
request:
enabled: true # 请求开启压缩
mime-types: text/xml,application/xml,application/json # 配置压缩支持的类型
min-request-size: 2048 # 压缩数据大小的下限
response:
enabled: true # 响应开启压缩
business业务服务
@GetMapping("/hello")
public String hello(@RequestParam("param") String param) {
String hello = feignDeviceService.hello(param);
log.info("收到hello:{}",hello);
return hello;
}
调用device设备服务的hello接口
@GetMapping("/hello")
public String hello(@RequestParam("param") String param, HttpServletRequest request) {
String hello = "hello: " + param + " 服务实例端口:" + request.getServerPort();// 当前实例端口号
log.info("hello:{}", hello);
return hello;
}
Feign开启GZIP压缩之后调用返回
看起来,跟没有开启压缩没什么两样,实际上通信效率是有提升的。
5.4.2 配置超时时间
feign:
client:
config:
default:
connectTimeout: 5000 # 连接超时
readTimeout: 5000 # 读取超时
loggerLevel: basic
5.4.3 Feign中的Ribbon超时配置
ribbon:
ReadTimeout: 5000 # 请求处理超时
ConnectTimeout: 5000 # 连接超时
5.5 Feign使用问题处理
5.5.1 替换默认的client
Feign原始的Http客户端没有连接池,对每个调用建立一个连接,存在较大的创建新连接的开销。通过替换Feign默认的连接池,我们可以复用连接,配置连接池大小,配置超时时间,使得Feign调用服务性能达到最优。
接下来,我们使用okhttp替换Feign默认的client。okhttp客户端真的很棒,它的牛x之处在于:
-
支持连接池,可以复用连接,减少创建连接开销,减少调用延迟
-
支持GZIP压缩,减少传输的数据量
-
合并多个到同一主机的请求
-
缓存响应,避免重复请求
1.首先我们引入okhttp依赖
在business业务服务工程中添加okhttp依赖
<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-okhttp</artifactId>
</dependency>
2.在配置文件中开启okhttp
feign:
okhttp:
enabled: true
3.在配置类中配置OkHttpClient对象并配置超时、连接池等参数
/**
* @description: 配置OkHttpClient,并设置超时参数、连接池参数
* @author:xg
* @date: 2024/12/26
* @Copyright:
*/
@Configuration
@ConditionalOnClass(Feign.class)
@AutoConfigureBefore(FeignAutoConfiguration.class)
public class FeignOkHttpConfig {
@Bean
public okhttp3.OkHttpClient okHttpClient() {
return new okhttp3.OkHttpClient.Builder()
// 连接超时
.connectTimeout(10, TimeUnit.SECONDS)
// 读超时
.readTimeout(10, TimeUnit.SECONDS)
// 写超时
.writeTimeout(10,TimeUnit.SECONDS)
// 自动重连
.retryOnConnectionFailure(true)
// 连接池
.connectionPool(new ConnectionPool())
.build();
}
}
4.最后启动business服务,device服务,然后进行Feign调用