一.简介
Feign是Netflix开发的一个轻量级RESTful的HTTP服务客户端(用它来发起请求,远程调用的),是以Java接口注解的方式调用Http请求,而不用像Java中通过封装HTTP请求报文的方式直接调用,Feign被广泛应用在Spring Cloud 的解决方案中。类似于Dubbo,服务消费者拿到服务提供者的接口,然后像调用本地接口方法一样去调用,实际发出的是远程的请求。
Feign可帮助我们更加便捷,优雅的调用HTTP API:不需要我们去拼接url然后呢调用restTemplate的api,在SpringCloud中,使用Feign非常简单,创建一个接口(在消费者--服务调用方这一端),并在接口上添加一些注解,代码就完成了。SpringCloud对Feign进行了增强,使Feign支持了SpringMVC注解(OpenFeign)。
Feign = RestTemplate+Ribbon+Hystrix
(本质:封装了Http调用流程,更符合面向接口化的编程习惯,类似于Dubbo的服务调用)
二. Feign配置应用
1. 服务消费者工程中引入Feign依赖(或者父类工程)导入如下依赖
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-openfeign</artifactId> </dependency |
2. 服务消费者工程启动类使用注解@EnableFeignClients添加Feign支持
@SpringBootApplication @EnableDiscoveryClient // 开启服务发现 @EnableFeignClients // 开启Feign public class PageApplication { public static void main(String[] args) { SpringApplication.run(PageApplication.class,args); } } |
3. 在消费者微服务中创建Feign接口
@FeignClient(name = "yang-service-product") public interface ProductFeign { /** * 通过id获取商品信息 * @param id * @return */ @RequestMapping("/product/query/{id}") public Products query(@PathVariable Integer id); /** * 获得端口号 * @return */ @RequestMapping("/server/query") public String findServerPort(); } |
注意事项:
1)@FeignClient注解的name属性用于指定要调用的服务提供者名称,和服务提供者yml文件中
spring.application.name保持一致
2)接口中的接口方法,就好比是远程服务提供者Controller中的Hander方法(只不过如同本地调用
了),那么在进行参数绑定的时,可以使用@PathVariable、@RequestParam、@RequestHeader
等,这也是OpenFeign对SpringMVC注解的支持,但是需要注意value必须设置,否则会抛出异常
3) @FeignClient(name = "yang-service-product"),name在消费者微服务中只能出现一次。(升级
Spring Boot 2.1.0 Spring Cloud Greenwich.M1 版本后,在2个Feign接口类内定义相同的名字,
@FeignClient(name = 相同的名字 就会出现报错,在之前的版本不会提示报错),所以最好将调用一个
微服务的信息都定义在一个Feign接口中。
4. 改造PageController中原有的调用方式
@RestController @RequestMapping("/page") public class PageController { @Autowired private ProductFeign productFeign; @RequestMapping("/getData/{id}") public Products findDataById(@PathVariable Integer id) { return productFeign.query(id); } @RequestMapping("/getPort") public String getProductServerPort() { return productFeign.findServerPort(); } } |
三. Feign对负载均衡的支持
Feign 本身已经集成了Ribbon依赖和自动配置,因此我们不需要额外引入依赖,可以通过
ribbon.xx 来进行全局配置,也可以通过服务名.ribbon.xx 来对指定服务进行细节配置配置.
配置添加如下代码:
#针对的被调用方微服务名称,不加就是全局生效 yang-service-product: ribbon: #请求连接超时时间 ConnectTimeout: 2000 #请求处理超时时间 ReadTimeout: 15000 #对所有操作都进行重试 OkToRetryOnAllOperations: true ####根据如上配置,当访问到故障请求的时候,它会再尝试访问一次当前实例(次数由MaxAutoRetries配置), ####如果不行,就换一个实例进行访问,如果还不行,再换一次实例访问(更换次数由MaxAutoRetriesNextServer配置), ####如果依然不行,返回失败信息。 MaxAutoRetries: 0 #对当前选中实例重试次数,不包括第一次调用 MaxAutoRetriesNextServer: 0 #切换实例的重试次数 NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule #负载策略调整 |
启动类添加相应注解:
@SpringBootApplication @EnableDiscoveryClient @EnableFeignClients //开启Feign客户端功能 public class PageApplication { public static void main(String[] args) { SpringApplication.run(PageApplication.class,args); } //像容器中注入一个RestTemplate,封装了HttpClient @Bean @LoadBalanced //启动请求的负载均衡 public RestTemplate restTemplate(){ return new RestTemplate(); } } |
Feign默认的请求处理超时时长1s,有时候我们的业务确实执行的需要一定时间,那么这个时候,我们就需要调整请求处理超时时长,Feign自己有超时设置,如果配置Ribbon的超时,则会以Ribbon的为准。
#针对的被调用方微服务名称,不加就是全局生效 yang-service-product: ribbon: #请求连接超时时间 #ConnectTimeout: 2000 #请求处理超时时间 #ReadTimeout: 5000 #对所有操作都进行重试 OkToRetryOnAllOperations: true ####根据如上配置,当访问到故障请求的时候,它会再尝试访问一次当前实例(次数由 MaxAutoRetries配置), ####如果不行,就换一个实例进行访问,如果还不行,再换一次实例访问(更换次数由 MaxAutoRetriesNextServer配置), ####如果依然不行,返回失败信息 MaxAutoRetries: 0 #对当前选中实例重试次数,不包括第一次调用 MaxAutoRetriesNextServer: 0 #切换实例的重试次数 NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RoundRobinRule #负载策略调整 |
四. Feign对熔断器的支持
1.在Feign客户端工程配置文件(application.yml)中开启Feign对熔断器的支持
# 开启Feign的熔断功能 feign: hystrix: enabled: true |
Feign的超时时长设置那其实就Ribbon的超时时长设置
Hystrix超时设置(就按照之前Hystrix设置的方式就OK了)
注意:
1)开启Hystrix之后,Feign中的方法都会被进行一个管理了,一旦出现问题就进入对应的回退逻辑处理。
2)针对超时这一点,当前有两个超时时间设置(Feign/hystrix),熔断的时候是根据这两个时间的最小值来进行的,即处理时长超过最短的那个超时时间了就熔断进入回退降级逻辑。
hystrix: command: default: circuitBreaker: # 强制打开熔断器,如果该属性设置为true,强制断路器进入打开状态,将会拒绝所有的请求。 默认false关闭的 forceOpen: false # 触发熔断错误比例阈值,默认值50% errorThresholdPercentage: 50 # 熔断后休眠时长,默认值5秒 sleepWindowInMilliseconds: 3000 # 熔断触发最小请求次数,默认值是20 requestVolumeThreshold: 2 execution: isolation: thread: # 熔断超时设置,默认为1秒 timeoutInMilliseconds: 5000 |
3) 自定义FallBack处理类(需要实现FeignClient接口)
接口:
@FeignClient(name = "yang-service-product",fallback = ProductFeignFallBack.class) public interface ProductFeign { /** * 通过商品id查询商品对象 * @param id * @return */ @GetMapping("/product/query/{id}") public Products queryById(@PathVariable Integer id); @GetMapping("/service/port") public String getPort(); } |
实现类:
@Component public class ProductFeignFallBack implements ProductFeign { @Override public Products query(Integer id) { return null; } @Override public String findServerPort() { return "-1"; } }
|
五. Feign对请求压缩和响应压缩的支持
Feign 支持对请求和响应进行GZIP压缩,以减少通信过程中的性能损耗。通过下面的参数 即可开启请求与响应的压缩功能。
feign: hystrix: enabled: true #开启请求和响应压缩 compression: request: enabled: true #默认不开启 mime-types: text/html,application/xml,application/json # 设置压缩的数据类型, 此处也是默认值 min-request-size: 2048 # 设置触发压缩的大小下限,此处也是默认值 response: enabled: true #默认不开启 |
ps:使用流程看起来蛮简单,真正动手操作,很多无脑问题就显现出来了