SpringCloud(一)【SpringCloud基础】
SpringCloud(二)【单体服务及远程调用】
SpringCloud(三)【Eureka注册中心】
SpringCloud(四)【Ribbon负载均衡】
SpringCloud(五)【Nacos注册中心】
Feign
一、Feign的基础使用
feign是一个声明式的HTTP客户端,可以让远程调用更加简单。即调用不同服务的接口,获取数据,因为在传统项目中是不能跨服务获取数据的。
使用步骤
- 导入依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
- 在启动类上添加注解开启Feign的功能
@EnableFeignClients
- 编写Feign客户端
@FeignClient("userservice")
public interface userFeignClient {
@GetMapping("/user/{id}")
User findById(@PathVariable("id") Long id);
}
- 代码调用
@Service
public class OrderService {
@Resource
private OrderMapper orderMapper;
@Resource
private RestTemplate restTemplate;
@Resource
private UserFeignClient userFeignClient;
public Order queryOrderById(Long orderId) {
// 1.查询订单
Order order = orderMapper.findById(orderId);
//restTemplate远程调用
/*
//2.利用restTemplate发起http请求
//String url = "http://localhost:8081/user/"+order.getUserId();
//使用服务名称、端口号 代替 ip、端口
String url = "http://userservice:8081/user/"+order.getUserId();
ResponseEntity<User> user = restTemplate.getForEntity(url, User.class);
order.setUser(user.getBody());
// 4.返回
return order;
*/
//Feign远程调用
User user = userFeignClient.findById(orderId);
order.setUser(user);
return order;
}
}
- 启动查看效果
可以看到实现了跨服务的数据获取。
注意:Feign不仅实现了远程调用,而且实现了负载均衡,因为Feign集成了Ribbon。
二、自定义Feign的配置
Feign运行自定义配置来覆盖默认配置,可以修改的配置如下:
一般只需要修改日志级别。
修改配置方式
方式一:配置文件方式
- 全局生效
feign:
client:
config:
default: #这里用default就是全局配置,如果是写服务名称,则是针对某个微服务的配置
loggerLevel: FULL #日志级别
- 部分生效
feign:
client:
config:
orderservice: #这里用default就是全局配置,如果是写服务名称,则是针对某个微服务的配置
loggerLevel: FULL #日志级别
方式二:Java代码方式
配置类
import feign.Logger;
import org.springframework.context.annotation.Bean;
public class FeignClientConfig {
@Bean
public Logger.Level feignLogLevel(){
return Logger.Level.BASIC;
}
}
- 全局生效
放在@EnableFeignClients
这个注解中
@EnableFeignClients(defaultConfiguration = FeignClientConfig.class)
- 部分生效
放在@FeignClient
这个注解中
@FeignClient(value = "userservice",configuration = FeignClientConfig.class)
三、Feign的性能优化
Feign底层的客户端实现
- URLConnection:默认实现,不支持连接池. Apache HttpClient :支持连接池
- OKHttp:支持连接池
优化思路
- 使用连接池替代默认的URLConnection
- 日志级别最好使用
basic
或者none
连接池配置方式
- 导入依赖
<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-httpclient</artifactId>
</dependency>
2. yml文件配置
feign:
httpclient:
enabled: true #支持HttpClient的开关,默认为true,但是未导入依赖不可用
connection-timeout: 200 #最大连接数
max-connections-per-route: 50 #单个路径的最大连接数
连接池的数量配置由压测结果来决定。
四、Feign的最佳实践
(一)继承
给消费者的FeignClient和提供者的controller定义统一的父接口作为标准。
缺点:
- 服务紧耦合;
- 父接口参数列表中的映射不会被继承。
(二)抽取
将FeignClient抽取为独立模块,并且把接口有关的POJO、默认的Feign配置都放到这个模块中,提供给所有消费者使用。
实现步骤:
- 首先创建一个module,命名为feign-api,然后引入feign的starter依赖
openfeign依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
-
将order-service中编写的UserClient、User、DefaultFeignConfiguration都复制到feign-api项目中
-
在order-service中引入feign-api的依赖
-
修改order-service中的所有与上述三个组件有关的import部分,改成导入feign-api中的包。
-
重启测试
出现问题:
启动失败。
报错:
A component required a bean of type ‘cn.min.feign.feign.UserFeignClient’ that could not be found.
原因:未在spring容器中创建对象
解决方案:
当定义的FeignClient不在SpringBootApplication的扫描包范围时,这些FeignClient无法使用。有两种方式解决:
- 全部引入(指定FeignClients所在的包)
@EnableFeignClients(basePackages = "cn.min.feign.feign")
- 只引入需要的(指定FeignClients字节码)
@EnableFeignClients(clients = {UserFeignClient.class})