背景:
Spring Cloud Ribbon:实现客户端负载均衡的服务调用
Spring Cloud Hystrix:通过断路由来保护微服务应用
在实际使用中,我们会发现Ribbon和Hystrix几乎是同时出现使用的。那么,Spring Cloud Feign就是一个整合Spring Cloud Ribbon和Spring Cloud Hystrix的工具,除了提供这两者强大的功能之外,还提供了一种声明式的Web服务客户端定义方式。
在使用Spring Cloud Ribbon时,通常都会利用它对RestTemplate的请求拦截来实现对以来服务的接口调用。而在Spring Cloud Feign的实现下,我们只需要创建一个接口并用注解的方式来配置它,即可完成对服务提供方接口的绑定,这样可以简化在使用Spring Cloud Ribbon时自行封装服务调用客户端的开发量。
一、快速入门
@FeignClient(value = "hello-service")
@Service
public interface HelloService {
@RequestMapping("/hello")
String hello();
}
以上代码中就是通过@FeignClient注解来绑定服务提供者(hello-service)的接口;通过Spring MVC的注解@RequestMapping注解来绑定具体调用helllo-service服务提供的哪一个REST接口。
具体例子请参考:Spring Cloud (十)、声明式服务调用Feign(入门)
二、参数绑定
如:带有Request参数请求、带有Header信息的请求、带有RequestBody的请求以及请求响应体中是一个对象的请求:
服务提供者:hello-service
/*带有Request参数的请求*/
@RequestMapping("/hello1")
public String hello(@RequestParam String name){
return "hello "+name;
}
/*带有Header信息的请求*/
@RequestMapping("/hello2")
public User hello(@RequestHeader String name,@RequestHeader Integer age){
return new User(name,age);
}
/*带有RequestBody的请求以及请求响应体是一个对象的请求*/
@RequestMapping("/hello3")
public String hello(@RequestBody User user){
return "hello "+user.getName()+","+user.getAge();
}
服务消费者:fegin-consume
@RequestMapping("/hello1")
String hello(@RequestParam("name") String name);
@RequestMapping("/hello2")
User hello(@RequestHeader("name") String name, @RequestHeader("age") Integer age);
@RequestMapping("/hello3")
String hello(@RequestBody User user);
注意:服务消费者的@RequestParam、@RequestHeader注解必须通过value值来指定具体的参数名。
具体例子请参考:Spring Cloud (十一)、Feign参数绑定
三、继承特性
继承特性帮助我们解决了复制相同代码的操作,以进一步减少了编码量。通过Spring Cloud Feign的继承特性来实现REST接口定义的复用。
优点:可以轻易地实现接口定义的共享
缺点:容易产生牵一发而动全身地后果
具体例子请参考:Spring Cloud (十二)、Feign的继承特性
四、Ribbon配置
对Ribbon的默认的配置主要是在DefaultClientConfigImpl类里面,我们搜索到这个类,然后查看默认配置。
1、全局配置:ribbon.
ribbon.DEFAULT_CONNECT_TIMEOUT=500
ribbon.DEFAULT_READ_TIMEOUT=5000
2、指定服务配置:
hello-service.ribbon.ConnectTimeout=500
hello-service.ribbon.ReadTimeout=5000
hello-service.ribbon.OkToRetryOnAllOperations=true
五、Hystrix配置
对Hystrix的默认配置主要是在HystrixCommandProperties类里面,我们搜索到这个类,然后查看默认配置。
1、全局配置
直接使用默认配置前缀hystrix.command.default就可以进行设置,比如设置全局的超时时间:
hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds=5000
在对Hystrix进行配置之前,我们需要确认feign.hystrix.enabled参数没有被设置为false(默认值就为false),否则该参数设置会关闭Feign客户端的Hystrix支持。
2、禁用Hystrix
feign.hystrix.enabled=false用来关闭Hystrix功能,这是全局的。如果只想针对某个服务客户端关闭Hystrix支持时,需要使用@Scope("prototype")注解为指定的客户端配置Feign.Builder实例,详细步骤如下:
(1)、构建一个关闭Hystrix的配置类
@Configuration
public class DisableHystrixConfiguration {
@Bean
@Scope("prototype")
public Feign.Builder feignBuilder(){
return Feign.builder();
}
}
(2)、在HelloService的@FeignClient注解中,通过configuration参数引入上面实现的配置类。
疑问???:这里我发先就算不进行configuration参数引入实现的配置类也能将Hystrix支持功能进行关闭,有兴趣的可再次进行验证。
@FeignClient(value = "hello-service",fallback = HelloServiceFallback.class,configuration = DisableHystrixConfiguration.class)
@Service
public interface HelloService {
@RequestMapping("/hello")
String hello();
@RequestMapping("/hello1")
String hello(@RequestParam("name") String name);
@RequestMapping("/hello2")
User hello(@RequestHeader("name") String name, @RequestHeader("age") Integer age);
@RequestMapping("/hello3")
String hello(@RequestBody User user);
}
这时我们在我们请求的时候,服务降级逻辑就不会生效,因为此时已经关闭了Hystrix的支持功能。
3、指定命令配置
hystrix.command.
hystrix.command.hello.execution.isolation.thread.timeoutInMilliseconds=5000
以上配置中的hello就是以下中hello方法名。
@FeignClient(value = "hello-service",fallback = HelloServiceFallback.class,configuration = DisableHystrixConfiguration.class)
@Service
public interface HelloService {
@RequestMapping("/hello")
String hello();
@RequestMapping("/hello1")
String hello(@RequestParam("name") String name);
@RequestMapping("/hello2")
User hello(@RequestHeader("name") String name, @RequestHeader("age") Integer age);
@RequestMapping("/hello3")
String hello(@RequestBody User user);
}
需要注意的是,由于方法名很有可能重复,这个时候相同方法名的Hystrix配置会共用,所以在进行方法定义与配置的时候需要做好一定的规划。
4、服务降级配置
(1)、只需要为Feign客户端的定义接口编写一个具体的接口实现类。其中每个重写方法的实现逻辑都可以用来定义相应的服务降级逻辑。
@Component
public class HelloServiceFallback implements HelloService {
@Override
public String hello() {
return "error";
}
@Override
public String hello(String name) {
return "error";
}
@Override
public User hello(String name, Integer age) {
return new User("未知",0);
}
@Override
public String hello(User user) {
return "error";
}
}
必须要使用@Component注解将其注入到容器中。
(2)、在服务绑定接口中,通过@FeignClient注解的fallback属性来指定对应的服务降级实现类。
@FeignClient(value = "hello-service",fallback = HelloServiceFallback.class)
@Service
public interface HelloService {
@RequestMapping("/hello")
String hello();
@RequestMapping("/hello1")
String hello(@RequestParam("name") String name);
@RequestMapping("/hello2")
User hello(@RequestHeader("name") String name, @RequestHeader("age") Integer age);
@RequestMapping("/hello3")
String hello(@RequestBody User user);
}
具体例子请参考:Spring Cloud (十三)、Feign服务降级配置
六、其他配置
1、请求压缩:Spring Cloud Feign支持对请求与响应进行GZIP压缩,以减少通信过程中的性能消耗。我们只需要通过下面两个参数设置,就能开启请求与响应的压缩功能:
feign.compression.request.enabled=true
feign.compression.response.enabled=true
同时,我们还能对请求压缩做一些更细致的设置,比如下面的配置内容指定了压缩的请求数据类型,并设置了请求压缩的大小下限,只有超过这个大小的请求才会对其进行压缩。
feign.compression.request.enabled=true
feign.compression.request.mime-types=text/xml,application/xml,application/json
feign.compression.request.min-request-size=2048
2、日志配置
可以在application.properties配置文件中使用loggin.level.
logging.level.com.example.feginconsume.Service.HelloService=debug
但是,只是添加了如上的配置,还无法实现DEBUG日志的输出。这是由于Feign客户端默认的Logger.Level对象定义为NONE级别,该级别不会记录任何Feign调用过程的信息,所以我们要调整它的级别:
针对全局的日志级别,可以在应用主类上添加Logger.Level的Bean创建,具体如下:
@EnableFeignClients
@EnableDiscoveryClient
@SpringBootApplication
public class FeginConsumeApplication {
@Bean
Logger.Level feignLoggerLevel(){
return Logger.Level.FULL;
}
public static void main(String[] args) {
SpringApplication.run(FeginConsumeApplication.class, args);
}
}
导入的日志包为import feign.Logger;
当然也可以通过实现配置类,然后在具体的Feign客户端来制定配置类以实现是否要调整不同的日志级别,比如下面的实现:
@Component
public class FullLogConfiguration {
@Bean
Logger.Level feignLoggetLevel(){
return Logger.Level.HEADERS;
}
}
@FeignClient(value = "hello-service",fallback = HelloServiceFallback.class,configuration = FullLogConfiguration.class)
@Service
public interface HelloService {
...
}
疑问???:这里我发先就算不进行configuration参数引入实现的配置类也能将日志信息进行调整,有兴趣的可再次进行验证。
对于Feign的Logger级别主要有下面四类,可根据实际需要进行调整使用: