Feign是一个声明性web服务客户端,它使得编写web服务客户端变得更加容易,Spring Cloud Feign是基于Netflix Feign实现,整合了Spring Cloud Ribbon与Spring Cloud Hystrix,除了提供两者强大功能外,它还提供了声明式的Web服务客户端定义方式
Feign是Spring Cloud组件中一个轻量级RESTful的HTTP服务客户端,Feign内置了Ribbon,用来做客户端负载均衡,去调用服务注册中心的服务。Feign的使用方式是:使用Feign的注解定义接口,调用接口,就可以调用服务注册中心的服务
引入依赖
org.springframework.boot
spring-boot-starter-feign
OpenFeign是Spring Cloud在Feign的基础上支持了SpringMVC的注解,如@RequestMapping等等。OpenFeign的@FeignClient可以解析SpringMVC的@RequestMapping注解下的接口,并通过动态代理的方式产生实现类
引入依赖
org.springframework.cloud
spring-cloud-starter-openfeign
参考代码: GitHub - PNZBEIJINGL/spring-cloud-lab
服务 | IP | 端口 | |
eureka-peer | 127.0.0.1 | 1000 | Eureka服务注册中心 |
openfeign-consumer | 127.0.0.1 | 8004 | 消费服务(测试Feign调用使用) |
ms-customer | 127.0.0.1 | 8001 | 客户服务 |
ms-customer_interface | 客户接口工程 | ||
2.1 ms-customer应用
提供2个RestController访问
/**
* http://127.0.0.1:8001/time/
*/
@RequestMapping(value = "/time", method = RequestMethod.GET)
public String time() {
return new Date().toString();
}
/**
* http://127.0.0.1:8001/customer/1
*/
@RequestMapping(value = "/{id}", method = RequestMethod.GET)
public CustomerDTO getCustomer(@PathVariable("id") Long customerId) throws InterruptedException {
//测试阻塞几秒
int sleepTime=new Random().nextInt(4000);
Thread.sleep(sleepTime);
ServiceInstance instance = discoveryClient.getLocalServiceInstance();
String message = " host:" + instance.getHost() + ",service_id:" + instance.getServiceId();
logger.info(message + " "+sleepTime);
CustomerDTO customer = mockCustomer();
customer.setId(customerId);
return customer;
}
2.2openfeign-consumer应用
feign-consumer应用的pom.xml配置增加依赖,并设置application.properties配置使用端口8004
org.springframework.boot
spring-boot-starter-web
org.springframework.cloud
spring-cloud-starter-eureka
org.springframework.cloud
spring-cloud-starter-openfeign
1.4.7.RELEASE
spring.cloud.test
ms-customer-interface
1.0.0
org.springframework.boot
spring-boot-test
test
server.port=8004
#服务的名称
spring.application.name=OPENFEIGN-CONSUMER
############ Eureka ################
#服务注册中心IP
eureka.instance.hostname=127.0.0.1
#指定服务注册中心
eureka.client.serviceUrl.defaultZone=http://${eureka.instance.hostname}:1000/eureka/
############ Eureka ################
启动主类增加@EnableFeignClients注解将Feign可用
@EnableDiscoveryClient
@EnableFeignClients
@SpringBootApplication
public class OpenfeignApplication {
public static void main(String[] args) {
SpringApplication.run(OpenfeignApplication.class, args);
}
}
创建CustomerService 接口,实现MS-CUSTOMER 服务调用
@FeignClient(value = "MS-CUSTOMER")
public interface CustomerService {
//不带参数
@RequestMapping("/time")
public String time() ;
//带参数
@RequestMapping(value = "/customer/{id}" ,method = RequestMethod.GET)
public String getCustomerById(@RequestParam("id") Long id);
}
创建OpenFeign测试接口
当访问http://127.0.0.1:8004/openfeign/gettime时候,调用CustomerService #time,实现调用访问
MS-CUSTOMER服务提供的服务 http://127.0.0.1:8001/time/
@RestController
public class TestCustomerController {
@Autowired
private CustomerService customerService;
//http://127.0.0.1:8004/openfeign/gettime
@RequestMapping(value = "/openfeign/gettime",method = RequestMethod.GET)
public String testMSCustomer(){
return customerService.time();
}
//http://127.0.0.1:8004/openfeign/getcustomer
@RequestMapping(value = "/openfeign/getcustomer", method = RequestMethod.GET)
public String testGetCustomerName(){
return customerService.getCustomerById(999L);
}
}
2.3 测试feign-consumer中的Feign调用
访问:http://127.0.0.1:8004/openfeign/gettime
访问http://127.0.0.1:8004/openfeign/getcustomer
修改FeignClient注解配置中的服务名,
@FeignClient(name = "${customer.server.name}")
public interface CustomerService {
//不带参数
@RequestMapping("/time")
public String time() ;
//带参数
@RequestMapping(value = "/customer/{id}" ,method = RequestMethod.GET)
public String getCustomerById(@RequestParam("id") Long id);
}
application.config中增加配置实现通过配置customer.server.name替代了服务名,
#客户服务名称配置,也可以配置到配置中心
customer.server.name=MS-CUSTOMER
访问 http://127.0.0.1:8004/openfeign/getcustomer
如果Hystrix在classpath同时 feign.hystrix.enabled=true,Feign将会用断路器包装所有的方法
#开启hystrix支持
feign.hystrix.enabled=true;
#属性用来配置HystrixCommand.run()的执行是否启动超时时间
#如果设置为false,hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds配置将会失效
#默认为true
hystrix.command.default.execution.timeout.enabled=true
#属性用来配置HystrixComman执行的超时时间,单位毫秒,当HystrixCommand执行时间
#超过配置的值后, Hystrix会执行命令标记为TIMOUT并进入服务降级处理逻辑
#默认1000毫秒
hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds=3000
通过@FeignClient注解中的 fallback实现Hystrix Fallback支持
@FeignClient(name = "${customer.server.name}" ,fallback = CustomerService.CustomerServiceFallback.class)
public interface CustomerService {
//不带参数
@RequestMapping("/time")
public String time() ;
//带参数
@RequestMapping(value = "/customer/{id}" ,method = RequestMethod.GET)
public String getCustomerById(@RequestParam("id") Long id);
@Component
class CustomerServiceFallback implements CustomerService{
@Override
public String time() {
return "fallback";
}
@Override
public String getCustomerById(Long id) {
return "fallback";
}
}
}
如果需要知道异常内容可以使用fallbackFactory 实现
@FeignClient(name = "${customer.server.name}" ,fallbackFactory = CustomerService.CustomerServiceFallbackFactory.class)
public interface CustomerService {
//不带参数
@RequestMapping("/time")
public String time() ;
//带参数
@RequestMapping(value = "/customer/{id}" ,method = RequestMethod.GET)
public String getCustomerById(@RequestParam("id") Long id);
static class CustomerServiceFallbackFactory implements FallbackFactory {
@Override
public CustomerService create(final Throwable cause) {
return new CustomerService() {
@Override
public String time() {
return "fallback,cause:" + cause.getMessage();
}
@Override
public String getCustomerById(Long id) {
return "fallback,cause:" + cause.getMessage();
}
};
}
}
}
注: 如果在测试过程中发现Incompatible fallback instance异常, 是因为@FeignClient注解中fallbackFactory 或者 fallback 设置的类不匹配引起
我们可以在客户端设置超时时间,OpenFeign超时时间有两种设置
feign.client.config.default.connectTimeout=5000
feign.client.config.default.readTimeout=5000
当服务器没有运行或者不可用,数据包会被连接拒绝,通信将会返回错误消息或者fallback信息,这可能是由于connectTimeout 设置的非常低造成的
当Hystrix 配置成可用的时候,其默认的超时时间是1000毫秒,我们设置的两种超时时间都在5000,因此它可能发生在我们配置的超时时间之前,因此增加超时时间可以防止这类情况发生。
当Hyestrix配置成可用且配置的时间比feign的超时时间长的候,HystrixTimeoutException异常将会包装feign的异常 ,HystrixTimeoutException异常的作用就是包装任何提前发生的运行时异常(Runtime exception) 然后抛出自身的实例
上一篇:Spring Cloud Feign启动Load balancer does not have available server for client