##一、什么是Feign
feign 是一种声明式的web 客户端,可以使用它的注解创建接口,它也支持自定义编解码。Spring Cloud 集成了Ribbon 和Eureka 为客户端提供了负载均衡策略。Feing有两个主要注解: (@EnableFeignClients 用于开启feign功能,@FeignClient 用于定义feign 接口)。
##二、 引入Feign
1、增加依赖
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-openfeign</artifactId> </dependency> 复制代码
2、Example spring boot app
@SpringBootApplication @EnableFeignClients public class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); } } 复制代码
StoreClient.java
@FeignClient("stores") public interface StoreClient { @RequestMapping(method = RequestMethod.GET, value = "/stores") List<Store> getStores(); @RequestMapping(method = RequestMethod.POST, value = "/stores/{storeId}", consumes = "application/json") Store update(@PathVariable("storeId") Long storeId, Store store); } 复制代码
在 @FeignClient 注解中这个("stores") 参数是一个唯一的名称(其实一般这个就是服务名称),用于创建Ribbon的负载均衡器。也能在其注解上使用url 参数(找个参数就是绝对路径了,如www.xxx.com)..这个Ribbon) 这个Ribbon client 将根据("stores") 发现物理地址,如果用了Eureka 那就会在其注册中心发现服务,如果没有使用也能配置一个外部列表。
##三、覆盖Feign默认属性
feign 组件中只要被@FeignClient 声明的就是一个客户端,我们可以通过使用FeignClientsConfiguration 创建我们自定义配置项,比如 feign.Decoder
, a feign.Encoder
, and a feign.Contract.
Example
@FeignClient(name = "stores", configuration = FooConfiguration.class) public interface StoreClient { //.. } 复制代码
在这个demo中 客户端由 FeignClientsConfiguration 和 FooConfiguration 两个组合而成(后边的配置会覆盖前面的)
FooConfiguration 这类不需要@Configuration 注解。如果加了这个你还需要在使用@ComponentScan 扫描的时候排除掉。否则这玩意就将成为 feign.Decoder
, feign.Encoder
, feign.Contract 的默认配置了。
@FeignClient 中 serviceId 属性已经废弃了,请注意。
在以前@FeignClient 中使用url时不需要配置name属性,现在这版本必须配置。
在 @FeignClient 的url 和name属性上可以使用占位符
@FeignClient(name = "${feign.name}", url = "${feign.url}") public interface StoreClient { //.. } 复制代码
Spring Cloud 为Feign 提供了一些默认的类
Decoder
feignDecoder: ResponseEntityDecoder
(which wraps a SpringDecoder
) Encoder
feignEncoder: SpringEncoder
Logger
feignLogger: Slf4jLogger
Contract
feignContract: SpringMvcContract
Feign.Builder
feignBuilder: HystrixFeign.Builder
Client
feignClient: 如果开启Ribbon 就是 LoadBalancerFeignClient
, 不开启的话就使用默认的。 默认情况下不提供下面的类,但是在创建客户端的时候也会去寻找加载,有的话就使用
Logger.Level Retryer ErrorDecoder Request.Options Collection<RequestInterceptor> SetterFactory
就跟上边的demo一样,创建一个类使用@FeignClient 配置其configuration (比如是这个FooConfiguration), Example
@Configuration public class FooConfiguration { @Bean public Contract feignContract() { return new feign.Contract.Default(); } @Bean public BasicAuthRequestInterceptor basicAuthRequestInterceptor() { return new BasicAuthRequestInterceptor("user", "password"); } } 复制代码
上面的配置就是 将SpringMvcContract 替换为feign.Contract.Default,并且添加了一个拦截器。当然也能使用配置文件配置@FeignClient 如下:
application.yml
eign: client: config: feignName: connectTimeout: 5000 readTimeout: 5000 loggerLevel: full errorDecoder: com.example.SimpleErrorDecoder retryer: com.example.SimpleRetryer requestInterceptors: - com.example.FooRequestInterceptor - com.example.BarRequestInterceptor decode404: false encoder: com.example.SimpleEncoder decoder: com.example.SimpleDecoder contract: com.example.SimpleContract 复制代码
当然这个配置类也能放在@EnableFeignClients 属性里面,但这么配置的话就是所以client 都生效了。如果你想配置所有的@FeignClient ,你可以使用默认的 default 作为feign名字,如下:
application.yml
feign: client: config: default: connectTimeout: 5000 readTimeout: 5000 loggerLevel: basic 复制代码
如果我们即创建了配置文件又创建了配置类,那配置文件的优先级最高,将覆盖配置类的属性。可以使用feign.client.default-to-properties=false 来改变这种特性。
如果你需要使用 ThreadLocal 绑定参数,你就需要设置Hystrix isolation 为SEMAPHORE
# To disable Hystrix in Feign feign: hystrix: enabled: false # To set thread isolation to SEMAPHORE hystrix: command: default: execution: isolation: strategy: SEMAPHORE 复制代码
##四、手动创建Feign客户端
在某些情况下上面的配置不能满足你的客户端,那就需要使用 Feign Builder API . 进行手动创建客户端。创建的时候可以使用不同的拦截器。
@Import(FeignClientsConfiguration.class) class FooController { private FooClient fooClient; private FooClient adminClient; @Autowired public FooController(Decoder decoder, Encoder encoder, Client client, Contract contract) { this.fooClient = Feign.builder().client(client) .encoder(encoder) .decoder(decoder) .contract(contract) .requestInterceptor(new BasicAuthRequestInterceptor("user", "user")) .target(FooClient.class, "http://PROD-SVC"); this.adminClient = Feign.builder().client(client) .encoder(encoder) .decoder(decoder) .contract(contract) .requestInterceptor(new BasicAuthRequestInterceptor("admin", "admin")) .target(FooClient.class, "http://PROD-SVC"); } } 复制代码
FeignClientsConfiguration 是cloud 默认的配置类,PROD-SVC 是服务名称。Contract用的是注入默认的。
##五、Feign Hystrix Fallbacks(降级)
降级概念:代码执行失败或者降级策略开启时,可以在@FeignClient设置一个fallback 属性实现这个降级策略。
@FeignClient(name = "hello", fallback = HystrixClientFallback.class) protected interface HystrixClient { @RequestMapping(method = RequestMethod.GET, value = "/hello") Hello iFailSometimes(); } static class HystrixClientFallback implements HystrixClient { @Override public Hello iFailSometimes() { return new Hello("fallback"); } } 复制代码
如果想知道降级的原因,就在@FeignClient 配置fallbackFactory 属性
FeignClient(name = "hello", fallbackFactory = HystrixClientFallbackFactory.class) protected interface HystrixClient { @RequestMapping(method = RequestMethod.GET, value = "/hello") Hello iFailSometimes(); } @Component static class HystrixClientFallbackFactory implements FallbackFactory<HystrixClient> { @Override public HystrixClient create(Throwable cause) { return new HystrixClient() { @Override public Hello iFailSometimes() { return new Hello("fallback; reason was: " + cause.getMessage()); } }; } } 复制代码
上面的demo简单的说了下怎么实现降级。但目前降级策略不支持方法返 com.netflix.hystrix.HystrixCommand
and rx.Observable 的情况。
##六、Feign 和 @Primary
当在Feign Hystrix使用降级策略时,如果在ApplicationContext 相同类型的实例。在使用@Autowired注入的时候就会报错,必须使用@Primary注解。为了正常运行,Spring Cloud 给所有的Feign实例都标记了@Primary 注解。但有些情况下这样就会有问题,所有提供了一个关闭的方法,可以将@FeignClient 属性primary设置为false.
FeignClient(name = "hello", primary = false) public interface HelloClient { // methods here } 复制代码
##七、Feign request/response 压缩 可以开启request/response GZIP压缩功能,配置属性就行了 feign.compression.request.enabled=true feign.compression.response.enabled=true
还有几个web server的配置 feign.compression.request.enabled=true feign.compression.request.mime-types=text/xml,application/xml,application/json feign.compression.request.min-request-size=2048
##八、Feign logging 可以使用全限定类名为Feing Client 创建一个记录器,记录器级别DEBUG logging.level.project.user.UserClient: DEBUG 可以配置Logger.Level 来设定怎么打印日志
NONE, 不打印 (DEFAULT). BASIC, 只记录请求方法和URL以及响应状态代码和执行时间 HEADERS, 记录基本信息以及请求和响应标头。 FULL, 记录请求和响应的头文件,正文和元数据
@Configuration public class FooConfiguration { @Bean Logger.Level feignLoggerLevel() { return Logger.Level.FULL; } } 复制代码