文章目录
- 一.概念
- 1.Feign是什么?
- 2.Feign有什么作用?
- 二.如何使用OpenFeign?
- 1.在OPenFeign消费端引入依赖
- 2.OpenFeign消费端启动类
- 3.在消费端创建service层(接口+注解)
- 4.消费端controller服务调用接口
- 5.效果
- 三.OpenFeign超时控制
- 1.在服务端编写延时暂停程序
- 2.在消费端调用延时暂停程序
- 3.测试
- 4.原因
- 5.解决方法
一.概念
1.Feign是什么?
Feign是一种负载均衡的HTTP客户端, 使用Feign调用API就像调用本地方法一样,从避免了调用目标微服务时,需要不断的解析/封装json 数据的繁琐。Feign集成了Ribbon。Ribbon+eureka是面向微服务编程,而Feign是面向接口编程。
Fegin是一个声明式的web服务客户端,它使得编写web服务客户端变得更加容易。使用Fegin创建一个接口并对它进行注解。它具有可插拔的注解支持包括Feign注解与JAX-RS注解,Feign还支持可插拔的编码器与解码器,Spring Cloud 增加了对 Spring MVC的注解,Spring Web 默认使用了HttpMessageConverters, Spring Cloud 集成 Ribbon 和 Eureka 提供的负载均衡的HTTP客户端 Feign。
2.Feign有什么作用?
Feign旨在使编写Java Http客户端变得更容易。在使用Ribbon+RestTemplate时,利用RestTemplate对http请求的封装处理,形成了一套模版化的调用方法。但是在实际开发中,由于对服务依赖的调用可能不止一处,往往一个接口会被多处调用,所以通常都会针对每个微服务自行封装一些客户端类来包装这些依赖服务的调用。所以,Feign在此基础上做了进一步封装,由他来帮助我们定义和实现依赖服务接口的定义。在Feign的实现下,我们只需创建一个接口并使用注解的方式来配置它(以前是Dao接口上面标注Mapper注解,现在是一个微服务接口上面标注一个Feign注解即可),即可完成对服务提供方的接口绑定,简化了使用Spring cloud Ribbon时,自动封装服务调用客户端的开发量。
Feign集成了Ribbon。利用Ribbon维护了MicroServiceCloud-Dept的服务列表信息,并且通过轮询实现了客户端的负载均衡。而与Ribbon不同的是,通过feign只需要定义服务绑定接口且以声明式的方法,优雅而简单的实现了服务调用。
二.如何使用OpenFeign?
1.在OPenFeign消费端引入依赖
<!--openfeign-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
2.OpenFeign消费端启动类
@SpringBootApplication
@EnableFeignClients
public class OrderFeignMain80 {
public static void main(String[] args) {
SpringApplication.run(OrderFeignMain80.class,args);
}
}
3.在消费端创建service层(接口+注解)
@Component
@FeignClient(value = "SPRINGCLOUD-PROVIDER-DEPT")
public interface DeptClientService {
@GetMapping("/dept/get/{id}")
public Dept queryById(@PathVariable("id") Long id);
@GetMapping("/dept/list")
public List<Dept> queryAll();
@PostMapping("/dept/add")
public boolean addDept(Dept dept);
}
消费端service层中的方法要与服务端controller接口中的方法对应
4.消费端controller服务调用接口
- 以前使用Ribbon+Eureka时:
@RestController
public class DeptConsumerController {
//消费者不应该有service层
//我们可以使用restTemplate直接调用
// 请求地址 http://localhost:8001/dept/get/1
/*
Ribbon。我们这里的地址应该是一个变量,通过服务名来访问
private static final String REST_URL_PREFIX="http://localhost:8001";
*/
private static final String REST_URL_PREFIX="http://SPRINGCLOUD-PROVIDER-DEPT";
//提供多种便捷访问远程http服务的方法
@Autowired
private RestTemplate restTemplate;
//调用服务提供者的add方法
@RequestMapping("/consumer/dept/add")
public boolean add(Dept dept){
return restTemplate.postForObject(REST_URL_PREFIX+"/dept/add",dept,Boolean.class);
}
//调用服务提供者的get方法
@RequestMapping("/consumer/dept/get/{id}")
public Dept get(@PathVariable("id") Long id){
return restTemplate.getForObject(REST_URL_PREFIX+"/dept/get/"+id,Dept.class);
}
//调用服务提供者的list方法
@RequestMapping("/consumer/dept/list")
public List<Dept> list(){
return restTemplate.getForObject(REST_URL_PREFIX+"/dept/list",List.class);
}
}
- 现在使用Feign,面向接口编程:
@RestController
public class DeptConsumerController {
@Autowired
private DeptClientService service=null;
//调用服务提供者的add方法
@RequestMapping("/consumer/dept/add")
public boolean add(Dept dept){
return this.service.addDept(dept);
}
//调用服务提供者的get方法
@RequestMapping("/consumer/dept/get/{id}")
public Dept get(@PathVariable("id") Long id){
return this.service.queryById(id);
}
//调用服务提供者的list方法
@RequestMapping("/consumer/dept/list")
public List<Dept> list(){
return this.service.queryAll();
}
}
5.效果
三.OpenFeign超时控制
1.在服务端编写延时暂停程序
- 服务提供方8001故意写暂停程序服务接口
@GetMapping(value = "/payment/feign/timeout")
public String paymentFeignTimeout(){
try { TimeUnit.SECONDS.sleep(3); }catch (Exception e) {e.printStackTrace();}
return serverPort;
}
2.在消费端调用延时暂停程序
- 服务消费方80在服务调用接口添加对应的超时方法PaymentFeignService
@GetMapping(value = "/payment/feign/timeout")
public String paymentFeignTimeout();
- 服务消费方80添加超时方法OrderFeignController
@GetMapping(value = "/consumer/payment/feign/timeout")
public String paymentFeignTimeout(){
return paymentFeignService.paymentFeignTimeout();
}
3.测试
- 输入:http://localhost:90/consumer/payment/feign/timeout
4.原因
- OpenFeign默认支持Ribbon,OpenFeign等待一秒钟,超过后报错
5.解决方法
- YML文件里需要开启OpenFeign客户端超时控制
#设置feign客户端超时时间(OpenFeign默认支持ribbon)
ribbon:
#指的是建立连接所用的时间,适用于网络状况正常的情况下,两端连接所用的时间
ReadTimeout: 5000
#指的是建立连接后从服务器读取到可用资源所用的时间
ConnectTimeout: 5000
- 测试结果: