【微服务】七. http客户端Feign

7.1 基于Feign远程调用

RestTimeplate方式调用存在的问题

先来看以前利用RestTemplate发起远程调用的代码:

java 复制代码
String  url = "http://userservice/user"+order.getUserId();
User user = restTemplate.getForObject(url,User.class);

存在下面的问题:

  • 代码可读性差,编程体验不统一
  • 参数复杂URL难以维护

Feign的介绍

Feign是一个声明式的http客户端,官方地址:https://github.com/OpenFeign/feign

其作用就是帮助我们优雅的实现http请求的发送,解决上面的问题。

定义和使用Feign客户端

使用Feign的步骤如下:

  • 引入依赖
xml 复制代码
<dependency>
	<groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
  • 在order-service的启动类添加注解开启Feign的功能:
java 复制代码
@EnableFeignClients  -- 开启feign注解
@MapperScan("cn.itcast.order.mapper")
@SpringBootApplication
 public class OrderApplication{
     public static void main(String[] args){
         SpringApplication.run(OrderApplication.class,args);
     }
 }
  • 编写Feign客户端
java 复制代码
@FeignClient("userservice")
public interface UserClient{
    @GetMapping("/user/{id}")
    User findById(@PathVariable("id") Long id);
}

主要是基于SpringMVC的注解来声明远程调用的信息,比如:

  • 服务名称:userservice
  • 请求方式:GET
  • 请求路径:/user/{id}
  • 请求参数:Long id
  • 返回值类型:User
  1. 用Feign客户端代替RestTemplate
java 复制代码
@Autowired
private UserClient userClient;

public Order queryOrderById(Long orderId){
	// 1. 查询订单
	Order order = orderMapper.findById(orderId);
	// 2. 利用Feign发起http请求,查询用户
	User user = userClient.findById(order.getUserId());
	// 3. 封装User到Order
	order.setUser(user);
	// 4. 返回
	return order; 
}

实际操作:

feign集成了ribbon,已经实现了负载均衡

总结

Feign的使用步骤:

  1. 引入依赖
  2. 添加@EnableFeignClients注解
  3. 编写FeignClient接口
  4. 使用FeignClient中定义的方法代替RestTemplate

7.2 自定义feign配置

Feign运行自定义配置来覆盖默认配置,可以修改的配置如下:

类型 作用 说明
feign.Logger.Level 修改日志级别 包含四种不同的级别:NONE、BASIC、HEADERS、FULL(一般情况下用basic或none,调试错误下用full)
feign.codec.Decoder 响应结果的解析器 http远程调用的结果做解析,例如解析json字符串为java对象
feign.codec.Encoder 请求参数编码 将请求参数编码,便于通过http请求发送
feign.Contract 支持的注解格式 默认是SpringMVC的注解
feign.Retryer 失败重试机制 请求失败的重试机制,默认是没有,不过会使用Ribbon的重试

一般我们需要配置的就是日志级别。

配置Feign日志有两种方式:

方式一:配置文件方式

全局生效:

yaml 复制代码
feign:
	client:
		config:
			default:  # 这里用default就是全局配置,如果是写服务名称,则是针对某个微服务的配置
				loggerLeverl: FULL # 日志级别

局部生效:

yaml 复制代码
feign:
	client:
		config:
			userservice: # 这里用default就是全局配置,如果是写服务名称,则是针对某个微服务的配置
				loggerLevel: FULL # 日志级别

方式二:java代码配置,需要先声明一个Bean

java 复制代码
public class FeignClientConfiguration{
	@Bean
	public Logger.Level feignLogLevel(){
		return Logger.Level.BASIC;  // 引入的包: feign.Logger
	}
}

而后,如果是全局配置,则把它放到@EnableFeignClients这个注解中:(加到启动类上)

java 复制代码
@EnableFeignClients(defaultConfiguration = FeignClientConfiguration.class);

如果是局部配置,则把它放到@FeignClient这个注解中:(加到具体的client接口上)

java 复制代码
@FeignClient(value = "userservice",configuration = FeignClientConfiguration.class);

总结

Feign的日志配置:

  1. 方式一是配置文件,feign.client.config.xxx,loggerLevel
  • 如果xxx是default则代表全局
  • 如果xxx是服务名称,例如userservice则代表某服务
  1. 方式二是java代码配置Logger.Level这个Bean
  • 如果是在@EnableFeignClients注解声明则代表全局
  • 如果在@EnableClient注解中声明则代表某服务

7.3 Feign的性能优化

7.3.1 Feign底层的客户端实现:

  • URLConnection:默认实现,不支持连接池
  • Apache HttpClient:支持连接池
  • OKHttp:支持连接池
    因为优化Feign的性能主要包括:
  • 使用连接池代替默认的URLConnection
  • 日志级别,最好用basic或none(默认none)

7.3.2 Feign的性能优化--连接池配置

Feign添加HttpClient的支持

引入依赖:

xml 复制代码
<!--httpClient的依赖-->
<dependency>
   <groupId>io.github.openfeign</groupId>
   <artifactId>feign-httpclient</artifactId>
</dependency>

配置连接池:

yaml 复制代码
feign:
	client:
		config:
			default: # default 全局的配置
				loggerLevel: BASIC # 日志级别,BASIC就是基本请求和响应
				
	httpclient:
		enbaled: true # 开启feign对HttpClient的支持
		max-connections: 200 # 最大的连接数
		max-connections-per-route: 50 # 每个路径的最大连接数

真实业务中要对程序进行压测,来具体确定max-connections、max-connections-per-route的值

总结:

Feign的优化:

  1. 日志级别尽量使用basic
  2. 使用HttpClient和OKHttp代替URLConnection
    引入feign-httpClient依赖
    配置文件开启httpClient功能,设置连接池参数

7.4 Feign最佳实践分析

方式一(继承):

给消费者的FeignClient和提供者的controller定义统一的父接口作为标准。

一般我们不推荐客户端和服务端之间共享一个interface,因为会造成紧耦合,而且对spring mvc不起作用

  • 服务紧耦合
  • 父接口参数列表中的映射不会被继承

方式二(抽取):

将FeignClient抽取为独立模块,并且把接口有关的POJO,默认的Feign配置都放到这个模块中,提供给所有的消费者使用

降低了耦合度,但是如果order-service只用feign-api中的两三个接口,需要把feign-api的所有都加载出来。

总结

Feign的最佳实践

  1. 让controller和FeignClient继承同一接口
  2. 将FeignClient、POJO、Feign的默认配置都定义到一个项目中,供所有消费者使用

7.5 实践:抽取FeignClient

抽取FeignClient

实现最佳实践方式二的步骤如下:

1.首先创建一个module,命名为feign-api,然后引入feign的starter依赖

2.将order-service中编写的UserClient、User、DefaultFeignConfiguration都复制到feign-api项目中

3.在order-service中引入feign-api的依赖

4.修改order-service中的所有与上述三个组件有关的import部分,改成导入feign-api中的包

5.重启测试

当定义的FeignClient不在SpringBootApplication的扫描包范围时,这些FeignClient无法使用。有两种方式解决:

方式一:指定FeignClient所在包(将所有的都拿过来)

java 复制代码
@EnableFeignClients(basePackages="cn.itcast.feign.clients")

方式二:指定FeignClient字节码(只拿UserClient)

java 复制代码
@EnableFeignClients(clients = {UserClient.clss})

总结

不同包的FeignClient的导入有两种方式:

1.在@EnableFeignClients注解中添加basePackages,指定FeignClient所在的包

2.在@EnableFeignClients注解中添加clients,指定具体FeignClient的字节码

相关推荐
_codemonster9 小时前
30分钟快速搭建 Spring Cloud Alibaba 微服务实战(一)
微服务·架构·毕业设计·课程设计
Dongwoo Jeong12 小时前
微服务架构(MSA)是如何诞生的?
微服务·云原生·架构
半旧夜夏12 小时前
【保姆级】微服务组件环境搭建(Docker Compose版)
java·linux·spring cloud·微服务·云原生·容器
西凉的悲伤20 小时前
Spring Boot 、Spring Cloud 微服务架构认证授权方案
spring boot·spring cloud·微服务·架构·认证授权
苏渡苇21 小时前
Seata 番外篇:使用 docker-compose 部署 Seata Server(TC)及 K8S 部署 Seata 高可用
spring boot·docker·微服务·容器·kubernetes·seata·springcloud
RingWu1 天前
高并发三板斧-异步
分布式·微服务·架构
雨辰AI1 天前
SpringBoot3 整合达梦 DM9 超详细入门实战|从零搭建可直接上线
数据库·微服务·架构·政务
Regentsoft丽晶软件3 天前
传统单体架构拖垮分销效率:2026品牌分销系统微服务化升级的价值拆解
微服务·云原生·架构
逻极3 天前
Go 从入门到精通:并发编程与云原生实践
微服务·云原生·go·并发
苏渡苇4 天前
强强联合:OpenFeign 整合 Sentinel
spring boot·spring cloud·微服务·sentinel·openfeign