OpenFeign教程
1、OpenFeign是什么?
OpenFeign是一个Web声明式的Http客户端调用工具。是Spring Cloud官方对Feign的增强,它支持spring mvc的注解。在Spring Cloud中使用OpenFeign,可以做到使用HTTP请求访问远程服务,就像调用本地方法一样。
2、环境准备
本文基于Springboot 2.6.8,服务注册中心使用的Nacos 版本用的最新的2021.0.1.0。看一下相关的Pom依赖
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<!-- spring-cloud-starter-alibaba-nacos-config -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
<version>2021.0.1.0</version>
</dependency>
<!-- spring-cloud-starter-alibaba-nacos-discovery -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
<version>2021.0.1.0</version>
<!--不使用Ribbon 进行客户端负载均衡-->
<exclusions>
<exclusion>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
<version>3.1.1</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-loadbalancer</artifactId>
<version>3.1.1</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-bootstrap</artifactId>
<version>3.0.4</version>
</dependency>
这里简单讲解一下,不是本文重点:
- 由于Ribbon停止维护,所以新版的SpringCloud已经不用它了,所以需要引入spring-cloud-starter-loadbalancer,并且在nacos依赖中排除掉ribbon。
- Springboot2.4+需要引入spring-cloud-starter-bootstrap
3、服务提供者
bootstrap.yml
server:
port: 8081
spring:
cloud:
nacos:
discovery:
server-addr: ip
service: provider
新建接口
@RestController
@RequestMapping("/provider")
public class ProviderController {
@PostMapping("/getOrder")
Order getOrder(@RequestBody OrderRequest request){
System.out.println(request.getId());
System.out.println(request.getClassify());
return Order.builder().code("JSON数据").build();
}
@GetMapping("/findOrder/{id}")
Order findOrder(@PathVariable("id") Integer id){
return Order.builder().id(id).count(50).code("URL携带参数").build();
}
@GetMapping("/findOrder")
Order findOrder(@SpringQueryMap OrderRequest request){
return Order.builder().code("POJO表单参数").build();
}
@GetMapping("/findOrder2")
Order queryOrder(@RequestParam("id") Integer id,
@RequestParam("code") String code){
System.out.println(id);
System.out.println(code);
return Order.builder().code("普通表单参数").build();
}
订单实体类
@Data
@Builder
public class Order {
private Integer id;
private String code;
private Integer userId;
private Integer count;
private BigDecimal money;
}
查询参数类
@Data
public class OrderRequest {
private Integer id;
private String name;
private String classify;
private Integer number;
}
4、服务消费者
bootstrap.yml
server:
port: 8082
spring:
cloud:
nacos:
discovery:
server-addr: ip
service: consumer
- @EnableFeignClients 启用Feign客户端
- @FeignClient 标记Feign客户端
在主程序的上加上注解@EnableFeignClients
新建一个接口 name填服务提供者注册到nacos的服务名
@FeignClient(name = "provider",path = "provider")
public interface FeignProviderService {
@PostMapping("/getOrder")
Order getOrder(@RequestBody OrderRequest request);
@GetMapping("/findOrder/{id}")
Order findOrder(@PathVariable("id") Integer id);
@GetMapping("/findOrder")
Order findOrder(@SpringQueryMap OrderRequest request);
@GetMapping("/findOrder2")
Order queryOrder(@RequestParam("id") Integer id,
@RequestParam("code") String code);
}
这样就可以在消费者的Service中直接注入使用
@Service("consumerService")
public class ConsumerServiceImpl implements ConsumerService {
@Autowired
FeignProviderService feignProviderService;
@Override
public Order dealOne() {
OrderRequest orderRequest = new OrderRequest();
orderRequest.setId(1);
orderRequest.setClassify("777");
return feignProviderService.getOrder(orderRequest);
}
@Override
public Order dealTwo() {
return feignProviderService.findOrder(2);
}
@Override
public Order dealThree() {
OrderRequest orderRequest = new OrderRequest();
orderRequest.setId(3);
orderRequest.setNumber(555);
return feignProviderService.findOrder(orderRequest);
}
@Override
public Order dealFour() {
return feignProviderService.queryOrder(4,"ORDER-FOUR");
}
}
5、传参问题
上文也看到我们在接口类中定义了不同传参方式的API
5.1 传递JSON数据
这个也是接口开发中常用的传参规则,在Spring Boot 中通过@RequestBody
标识入参。openFeign默认的传参方式就是JSON传参(@RequestBody
),因此定义接口的时候可以不用@RequestBody
注解标注,不过为了规范,一般都填上。
5.2 POJO表单传参
openFeign提供了一个注解@SpringQueryMap
完美解决POJO表单传参。
5.3 URL携带参数
此种方式针对restful方式中的GET请求,也是比较常用请求方式。
5.4 普通传参
这种不管调用方还是被调用方都加上@RequestParam注解
6、超时处理
如果连接或者读取时间超过了默认超时时间,消费者端就会报超时。
旧版本集成Ribbon如果不设置超时时间,默认超时时间为1s,新版不用Ribbon了。
在消费端的配置文件中配置超时时间
feign:
client:
config:
## default 设置的全局超时时间,指定服务名称可以设置单个服务的超时时间
default:
connectTimeout: 5000
readTimeout: 5000
还可以给单个服务配置超时时间,单个配置的超时时间将会覆盖全局配置。
feign:
client:
config:
## default 设置的全局超时时间,指定服务名称可以设置单个服务的超时时间
default:
connectTimeout: 5000
readTimeout: 5000
## 为serviceC这个服务单独配置超时时间
serviceC:
connectTimeout: 30000
readTimeout: 30000
7、开启日志增强
feign的日志级别
- NONE: 默认的,不显示任何日志
- BASIC: 仅记录请求方法、URL、响应状态码以及执行时间
- HEADERS:除了BASIC 中自定义的信息外,还有请求和响应的信息头
- FULL: 除了HEADERS中定义的信息外, 还有请求和响应的正文以及元数据。
前提条件需要在配置文件中,将日志级别设置为DEBUG。我们修改一下消费者的配置文件
feign:
client:
config:
## default 设置的全局超时时间,指定服务名称可以设置单个服务的超时时间
default:
connectTimeout: 5000
readTimeout: 5000
loggerLevel: basic
logging:
level:
#feign接口path
com.example.consumer.client.FeignProviderService: debug
再次调用服务可以看到控制台有相关日志了
8、替换默认HttpClient
ApacheHttpClient和默认实现的比较
- Feign在默认情况下使用的是JDK原生的URLConnection发送HTTP请求,没有连接池,但是对每个地址会保持一个长连接,即利用HTTP的persistence connection。
- ApacheHttpClient实现了连接池,同时它封装了访问http的请求头,参数,内容体,响应等等,使客户端发送 HTTP 请求变得容易
添加依赖
<!-- httpclient -->
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5.13</version>
</dependency>
<!-- feign-httpclient -->
<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-httpclient</artifactId>
<version>10.10.1</version>
</dependency>
可以看到,默认就是开启的
9、工作原理
远程调用基本流程
其中 MethodHandler 的invoke(…)方法,主要职责是完成实际远程URL请求,然后返回解码后的远程URL的响应结果
- 点赞
- 收藏
- 关注作者
评论(0)