6.http客户端Feign
6.1 Feign代替RestTemplate
RestTemplate缺点:代码可读性差;url维护不方便
Feign:一个声明式的http客户端,优雅地实现http请求的发送,官网 RPC(远程过程调用)
原理:基于接口的动态代理(动态代理应用:AOP)
定义和使用
1.引入feign依赖
<!--feign客户端依赖-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
2.添加注解@EnableFeignClients
开启feign功能-order-service
@MapperScan("cn.itcast.order.mapper")
@SpringBootApplication
@EnableFeignClients
public class OrderApplication {
public static void main(String[] args) {
SpringApplication.run(OrderApplication.class, args);
}
@Bean
@LoadBalanced
public RestTemplate restTemplate() {
// todo 据说官方推荐RestTemplateBuilder
return new RestTemplate();
}
}
3.编写Feign客户端
@FeignClient("user-service")
public interface UserClient {
@GetMapping("/user/{id}")
User findById(@PathVariable("id") Long id);
}
4.使用feign进行http访问
@Autowired
private UserClient userClient;
public Order queryOrderById(Long orderId){
Order order = orderMapper.findById(orderId);
if(null!=order && null!=order.getUserId()){
//类型解析
ObjectMapper mapper = new ObjectMapper();
User user = mapper.convertValue(result.getData(),User.class);
order.setUser(user);
}
return order;
}
6.2 自定义配置

由于新版(4.0.2)的Feign已经不支持yml文件自定义配置了,所以需要编写配置类
1.编写配置类
public class UserFeignConfig {
//feign4.0.2貌似不支持yml文件配置feign,所以使用配置类的方式实现覆写配置
//自定义feign的配置
//定义日志输出级别
@Bean
public Logger.Level feignLoggerLevel(){
return Logger.Level.FULL;
}
}
2.在自定义的FeignClient中声明要加载的配置类configuration
@FeignClient(value = "user-service",configuration = UserFeignConfig.class)
public interface UserClient {
@GetMapping("/user/{id}")
Result findById(@PathVariable("id") Long id);
}
3.如果是全局配置,则需要把config文件写在全局注解里
@EnableFeignClients(defaultConfiguration=UserFeignConfig.class)
public class OrderApplication(...){
...
}
⭐为什么把FeignClient定义为接口而不是类:
- Feign是一个声明式的REST客户端,可以根据接受定义来生成HTTP客户端代码,并将HTTP请求映射到接口方法上,从而实现了简易的REST调用.在feign中,需要定义一个接口来描述REST接口的URL、HTTP方法、请求参数和请求头等信息,然后使用注解来描述请求参数和返回值的格式,Feign就会根据这些信息生成HTTP客户端代码.
- 简化客户端开发,只需要定义接口,避免手动构建HTTP请求
- 提高代码可读性和可维护性
6.3 Feign使用优化

步骤:
1.替换默认URLConnection,在pom中引入新的客户端依赖
<!--代替feign默认的URLConnection,使用带有连接池的客户端-->
<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-httpclient</artifactId>
</dependency>
2.配置最大连接数等信息
spring:
cloud:
openfeign:
httpclient:
# 开启httpclient的开关,默认为true
enabled: true
# 最大连接数和单个路径的最大连接数,需要通过实际ya'li'v'c
max-connections: 200
max-connections-per-route: 50
6.4 最佳实践
1.因为服务消费者能够调用的http方法来自于服务提供者的已有方法,所以可以为消费者的FeignClient和提供者的controller定义统一的父接口


eg.采用方式二.
创建一个子模块feign-api,在order-service中引入子模块的dependency并使用.
bug&debug:


bug:使用@Autowired注解注入UserClient时报错,启动OrderApplication失败,提示userclient为空。
思路:文件中已经引入了userclient,说明spring是可以找到这个接口的,但是userclient仍然为空是因为spring并没用使用动态代理为其生成bean对象.
原因:order-service默认只扫描OrderApplication所在的包并为其生成bean对象,而userclient不在这里,故没有bean对象.

debug:
方法一:在EnableFeignClients
注解中指明FeignClient所在package
@EnableFeignClients(basePackages = "cn.itcast.feign.clients")
方法二:在EnableFeignClients
注解中指明字节码
@EnableFeignClients(clients = {UserClient.class})