SpringCloud之Feign代理,声明式服务调用方式
作者:择业
将其他微服务中的服务接口,用feign在本项目中进行调用。
Spring Cloud Feign是一套基于Netflix Feign实现的声明式服务调用客户端。它使得编写Web服务客户端变得更加简单。我们只需要通过创建接口并用注解来配置它既可完成对Web服务接口的绑定。它具备可插拔的注解支持,包括Feign注解、JAX-RS注解。它也支持可插拔的编码器和解码器。Spring Cloud Feign还扩展了对Spring MVC注解的支持,同时还整合了Ribbon和Hystrix来提供均衡负载的HTTP客户端实现。
对于Feign来讲,其实就是一个WEB接口而已,它内部自集成了Spring Ribbon 和Spring Hystrix 断路器功能,也就是说可以支持自动降级和负载均衡功能。可以说,在内部服务与服务之间的相互数据通信桥梁就是通过Feign来实现的。也就是说,我们可以像使用web service OR dubbo 一样对其进行声明式的配置,这非常棒~ 在我之前的工作中,就大量的使用了Feign代理,可以说使用spring cloud 就必须要学会如何深入使用Feign代理,当然它也非常的简单。
引入相关依赖然后再主入口启用注解
@EnableFeignClients //启用代理服务 @EnableCircuitBreaker //启用断路器

引入相关依赖然后再主入口启用注解:@Enabl

注意:我们feign在第四个版本后需要手工的开启断路器功能才可以生效。
了解完Feign的基础配置之后,我们当然要开始代码实现了。首先我们需要编写一个interface,并且这个interface一定是已知的服务(也就是注册到了Eureka上的接口服务,我们在这里需要使用interface的方式进行声明)
@FeignClient注解就是Feign的注解声明了,里面name属性表示了当前代理的服务APP NAME; fallback属性当然就是我们调用服务失败的降级策略了,也就是当网络闪段、异常等调用代理服务失败时,会根据断路器的超时时间降级到指定的fallback所赋予的HelloServiceHystrix类中,我们可以进行降级处理。


我们的Feign底层默认提供了重试机制,也就是底层使用Retryer类对调用服务进行重试调用操作,通过底层代码我们知道默认是每100ms去进行调用,调用次数是5次。既然Feign集成了Ribbon 与 Hystrix ,那么必然会使用两个超时机制,一个是Ribbon的超时时间,一个是Hystrix的超时时间.这两个超时时间的含义截然不同,千万要注意配置。
经验小结: 我们可以配置Hystrix的超时时间大于Ribbon的超时时间。并且如果想进行重试最好是Hystrix的超时时间设置为Ribbon的超时时间的倍数。
这样我们可以进行重试策略,如果Hystrix的超时时间小于Ribbon的超时时间,则不会重试,直接被断路器组件对调用请求执行请求段熔机制,服务降级。
Feign配合Ribbon、Hystrix的超时策略配置如下

1.pom
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <parent> <artifactId>com.zx.dt2b.erp</artifactId> <groupId>com.zx.dt2b.erp</groupId> <version>1.0-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> <artifactId>feign</artifactId> <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.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-hystrix</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-feign</artifactId> </dependency> </dependencies> <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <!-- <version>Dalston.SR5</version> --> <version>Edgware.SR4</version> <!-- <version>Finchley.SR1</version> --> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> <build> <finalName>feign</finalName> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> <configuration> <mainClass>com.zx.dt2b.FeignApplication</mainClass> </configuration> </plugin> </plugins> </build> </project>
2.主入口
package com.zx.dt2b;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.netflix.feign.EnableFeignClients;
@EnableFeignClients //启用代理服务
@EnableCircuitBreaker //启用断路器
@EnableDiscoveryClient //标识具体的一个服务,需要向注册中心注册
@SpringBootApplication //SpringBoot 核心配置
public class FeignApplication {
public static void main(String[] args) {
SpringApplication.run(FeignApplication.class, args);
}
}3.配置文件
feign: hystrix: enabled: true #开启降级 compression: request: min-request-size: 2048 mime-types: - text/html, application/xml, application/json spring: application: name: feign-consumer cloud: loadbalancer: retry: enabled: true server: context-path: / port: 7005 eureka: client: service-url: defaultZone: http://eureka1:8001/eureka feign: hystrix: enabled: true compression: request: min-request-size: 2048 mime-types: - text/html, application/xml, application/json ##设置断路器的超时时间 hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds: 10000 ##微服务的请求配置 customer-service: ConnectTimeout: 10000 ReadTimeout: 3000 ribbon: OkToRetryOnAllOperations: true ##对所有的请求都进行重试 MaxAutoRetriesNextServer: 1 ##切换实例的次数 MaxAutoRetries: 2 ##对当前实例重试的次数
4.业务代码与实现
@FeignClient(name="provider-service", fallback= IndexFeignFailback.class)
name表示微服务名称:前端直接从本项目访问其他项目服务接口
失败后IndexFeignFailback中对应的接口,进行降级。
代理服务中异常等要保持一致
package com.zx.dt2b.feign;
import com.zx.dt2b.feign.hystrix.IndexFeignFailback;
import org.springframework.cloud.netflix.feign.FeignClient;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
@FeignClient(name="customer-service", fallback= IndexFeignFailback.class)
public interface IndexFeignClient {
@RequestMapping(value="/customerservice/index", method = {RequestMethod.GET})
public String hello() throws Exception;
@RequestMapping(value="/customerservice/hi", method = {RequestMethod.GET})
public String hi() throws InterruptedException;
}package com.zx.dt2b.feign.hystrix;
import com.zx.dt2b.feign.IndexFeignClient;
import org.springframework.stereotype.Component;
@Component
public class IndexFeignFailback implements IndexFeignClient {
@Override
public String hello() throws Exception {
return "-----hello接口的降级方法!--------";
}
@Override
public String hi() throws InterruptedException {
return "-----hi接口的降级方法!--------";
}
}5.controller测试
package com.zx.dt2b.api;
import com.zx.dt2b.feign.IndexFeignClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class ConsumerController {
@Autowired
private IndexFeignClient indexFeignClient;
@RequestMapping(value="/feign-hello")
public String hello() throws Exception {
return indexFeignClient.hello();
}
@RequestMapping(value="/feign-hi")
public String hi() throws InterruptedException {
return indexFeignClient.hi();
}
}以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。
