1 简介
在前面的学习中,我们使用RestTemplate调用外部接口,如果就学到这里,你可能以后需要编写类似的大量重复代码,格式基本相同,无非参数不一样。有没有更优雅的方式,来对这些代码再次优化呢?
这就是我们接下来要学的Feign的功能了。
项目主页:github
Feign可以把Rest的请求进行隐藏,伪装成类似SpringMVC的Controller一样。你不用再自己拼接url,拼接参数等等操作,一切都交给Feign去做。
Feign是一个声明式WebService客户端,使用Feign能让编写WebService客户端更加简单。也支持可插拔式的编码器和解码器。SpringCloud对feign进行了封装,使其支持了SpringMVC标准注解和HttpMessageConverts,Feign整合Ribbon和Eureka以支持负载均衡。
关于Feign的介绍:https://blog.csdn.net/wyaoyao93/article/details/111238858
2 使用OpenFeign替换RestTemplate
接口+注解
- 创建一个模块:消费者模块
cloud-consumer-order-feign
,来演示feign的基本使用,导入依赖,本次核心就是openfeign的依赖啦。
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--监控-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!--引入我们的api-common-->
<dependency>
<groupId>study.wyy</groupId>
<artifactId>cloud-api-common</artifactId>
<version>${project.version}</version>
</dependency>
<!--使用Eureka做注册中心-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<!--open feign-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
</dependencies>
- application.yml配置: 和之前的服务消费者订单服务没有任何变化
server:
port: 80
eureka:
client:
register-with-eureka: false
service-url:
defaultZone: http://localhost:7001/eureka/
- 启动类:使用@EnableFeignClients开启Feign
package study.wyy.cloud.feign.order;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.openfeign.EnableFeignClients;
/**
* @author by wyaoyao
* @Description
* @Date 2020/12/20 8:25 上午
*/
@SpringBootApplication
@EnableFeignClients
public class OrderApplicationFeign {
public static void main(String[] args) {
SpringApplication.run(OrderApplicationFeign.class,args);
}
}
- 定义一个Feign的接口
package study.wyy.cloud.feign.order.service;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import study.wyy.cloud.api.model.CommonResult;
import study.wyy.cloud.api.model.Payment;
/**
* @author by wyaoyao
* @Description
* @Date 2020/12/20 8:40 上午
*/
/******
* @FeignClient: value属性指定调用的服务在注册中心上的名字
*/
@FeignClient(value = "cloud-payment-service")
public interface PaymentService {
/*****
* 调用支付服务的id查询方法
* @param id
* @return
*/
@GetMapping("/payment/{id}")
public CommonResult<Payment> invokeFindById(@PathVariable("id") Long id);
/*****
* 调用支付服务的创建支付单方法
* @param
* @return
*/
@PostMapping("/payment/create")
public CommonResult<Integer> create(@RequestBody Payment payment);
}
- 之前通过restTemplate 改为使用Feign调用
package study.wyy.cloud.feign.order.controller;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
import study.wyy.cloud.api.model.CommonResult;
import study.wyy.cloud.api.model.Payment;
import study.wyy.cloud.feign.order.service.PaymentService;
/**
* @author by wyaoyao
* @Description
* @Date 2020/12/20 9:10 上午
*/
@RestController
@Slf4j
public class OrderController {
private final PaymentService paymentService;
public OrderController(PaymentService paymentService) {
this.paymentService = paymentService;
}
@GetMapping("/consume/payment/create/{serial}")
public CommonResult consumeCreatePayment(@PathVariable("serial") String serial){
Payment payment = new Payment();
payment.setSerial(serial);
//CommonResult commonResult = restTemplate.postForObject(PAYMENT_ADDRESS + "/payment/create", payment, CommonResult.class);
// 之前通过restTemplate 改为使用Feign调用
CommonResult<Integer> commonResult = paymentService.create(payment);
return commonResult;
}
@GetMapping("/consume/payment/find/{id}")
public CommonResult consumeFindPayment(@PathVariable("id") Long id){
System.out.println(1111);
// CommonResult commonResult = restTemplate.getForObject(PAYMENT_ADDRESS + "/payment/" + id, CommonResult.class);
// 之前通过restTemplate 改为使用Feign调用
CommonResult<Payment> paymentCommonResult = paymentService.invokeFindById(id);
return paymentCommonResult;
}
}
- 测试
- 启动注册中心Eureka-Server
- 启动服务提供者支付服务
- 启动服务消费者订单服务
分别访问:
http://localhost/consume/payment/create/2020
{"code":200,"message":"create.success8001","data":1}
http://localhost/consume/payment/find/1
{"code":200,"message":"find.success8001","data":{"id":1,"serial":"2020"}}
3 超时控制
Feign客户端默认超时时间是1秒,但是服务端链路过长又或者网络问题出现超时现象,客户端就会返回超时报错。
如何设置调用超时时间:
ribbon:
# 建立链接之后读取资源的超时时间
ReadTimeout: 5000
# 建立链接超时时间
ConnnectTimeout: 5000