Feign 是一个声明性 Web 服务客户端。它使编写 Web 服务客户端更加容易。要使用 Feign,请创建一个接口并对其进行注解。它具有可插入的注解支持,包括外部注解和 JAX-RS 注解。Feign 还支持可插拔的编码器和解码器。Spring Cloud 增加了对 Spring MVC 注解的支持,以及对使用 Spring Web 中默认使用的相同
要在项目中包含 Feign,请使用 group ID 为 示例 spring boot 应用 @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); }
在 上面的 Ribbon 客户端将希望发现 "stores" 服务的物理地址。如果你的应用程序是 Eureka 客户端,那么它将解析 Eureka 服务注册表中的服务。如果你不想使用 Eureka,只需在外部配置中配置服务器列表(请参见上面的示例)。
Spring Cloud 的 Feign 支持的一个核心概念是命名客户端。每个虚拟客户端都是一组组件的一部分,这些组件共同工作以按需联系远程服务器,并且该集合有一个名称,你可以使用
Spring Cloud 允许你通过使用 @FeignClient(name = "stores", configuration = FooConfiguration.class) public interface StoreClient { //.. }
在这种情况下,客户端由已经在
@FeignClient(name = "${feign.name}", url = "${feign.url}") public interface StoreClient { //.. }
Spring Cloud Netflix 默认为 feign 提供以下 bean(
通过分别将 默认情况下,Spring Cloud Netflix 不提供以下 bean 用于 feign,但仍然从应用程序上下文中查找这些类型的 bean 以创建 feign 客户端:
创建一个这种类型的 bean 并将其放置在 @Configuration public class FooConfiguration { @Bean public Contract feignContract() { return new feign.Contract.Default(); } @Bean public BasicAuthRequestInterceptor basicAuthRequestInterceptor() { return new BasicAuthRequestInterceptor("user", "password"); } }
这将使用
application.yml feign: 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
默认配置可以在
如果你喜欢使用配置属性来配置所有 application.yml feign: client: config: default: connectTimeout: 5000 readTimeout: 5000 loggerLevel: basic
如果我们同时创建
application.yml # 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 创建客户端。下面是一个示例,它创建了两个具有相同接口的 Feign 客户端,但使用单独的请求拦截器配置每个客户端。 @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"); } }
如果 Hystrix 在类路径上,并且
要在每个客户端基础上禁用 Hystrix 支持,请创建一个具有 "prototype" 范围的普通 @Configuration public class FooConfiguration { @Bean @Scope("prototype") public Feign.Builder feignBuilder() { return Feign.builder(); } }
Hystrix 支持回退的概念:一个默认的代码路径,当它们的电路断开或出错时执行。要为给定的 @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(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()); } }; } }
在对 Hystrix 回退使用 Feign 时,同一类型的 @FeignClient(name = "hello", primary = false) public interface HelloClient { // methods here } Feign 通过单个继承接口支持样板 API。这允许将公共操作分组到方便的基本接口中。 UserService.java. public interface UserService { @RequestMapping(method = RequestMethod.GET, value ="/users/{id}") User getUser(@PathVariable("id") long id); } UserResource.java. @RestController public class UserResource implements UserService { } UserClient.java. package project.user; @FeignClient("users") public interface UserClient extends UserService { }
你可以考虑为你的 Feign 请求启用请求或响应 GZIP 压缩。可以通过启用以下属性之一来执行此操作: feign.compression.request.enabled=true feign.compression.response.enabled=true Feign 请求压缩为你提供的设置与你可能为 web 服务器设置的设置类似: feign.compression.request.enabled=true
feign.compression.request.mime-types=text/xml,application/xml,application/json
feign.compression.request.min-request-size=2048
这些属性允许你选择压缩媒体类型和最小请求阈值长度。
为创建的每个 Feign 客户端创建一个记录器。默认情况下,日志记录器的名称是用于创建 Feign 客户端的接口的完整类名。Feign 日志只响应 application.yml. logging.level.project.user.UserClient: DEBUG
你可以为每个客户端配置
例如,下面将 @Configuration public class FooConfiguration { @Bean Logger.Level feignLoggerLevel() { return Logger.Level.FULL; } }
OpenFeign
Spring Cloud OpenFeign 提供了等效的
例如, // Params.java public class Params { private String param1; private String param2; // [Getters and setters omitted for brevity] }
以下 feign 客户端使用 @FeignClient("demo") public class DemoTemplate { @GetMapping(path = "/demo") String demoEndpoint(@SpringQueryMap Params params); } |