OpenFeign 2.1.4 Release文档翻译版

OpenFeign 2.1.4 Release Doc

这个项目通过自动装配和其他Spring程序模型的习惯用法,把给SpringBoot应用提供的OpenFeign的综合包绑定到Spring的项目环境中。

1 说明

Feign是一个声明式的web服务客户端。它使编写web服务客户端变得更加简单。创建一个接口和注解就能使用Feign。它有可插入的注解支持,包括Feign的注解和JAXRS注解。Feign也支持可插入的编码器和解码器。SpringCloud为Spring MVC 注解和在Spring Web中使用相同的HttpMessageConverters,提供了支持。SpringCloud合并了Ribbon和Eureka,而且在使用Feign时,Spring Cloud LoadBalancer 提供了一个负载均衡的http客户端。

1.1 如何添加Feign

要在你的项目中加入Feign,使用group为org.springframework.cloud,artifact id为spring-cloud-starter-openfeign的starter。

使用Feign时要在启动类中加入注解:

@SpringBootApplication
@EnableFeignClients
public class Application {

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }

}

Feign的接口声明:

@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负载均衡器(有关Ribbon支持的详细信息,请参阅下面)或Spring Cloud LoadBalancer。还可以使用URL属性(绝对值或主机名)指定URL。应用程序上下文中bean的名称是接口的完全限定名。要指定自己的别名值,可以使用@FeignClient注释的限定符值。

上面的负载均衡器客户机希望发现“stores”服务的物理地址。如果您的应用程序是一个Eureka客户端,那么它将在Eureka服务注册表中解析服务。如果您不想使用Eureka,您可以简单地在外部配置中配置一个服务器列表(参见上面的示例)。

注意:为了保持向后兼容性,被用作默认的负载平衡器实现。但是,Spring Cloud Netflix Ribbon现在处于维护模式,所以我们建议使用Spring Cloud LoadBalancer来代替。为此,设置spring.cloud.loadbalker .ribbon.enabled为false。

1.2 重写Feign默认实现

SpringCloud的Feign支持的核心概念是客户端的名称。每一个Feign客户端,都是根据需要联系远程服务器一起工作的整体组件的一部分,你要用@FeignClient注解为这个整体指定一个名字。SpringCloud会按需为每一个使用FeignClientsConfiguration的客户端创建一个新的整体作为一个ApplicationContext。ApplicationContext包括了一个 feign.Decoder,一个 feign.Encoder,一个 feign.Contract。你可以使用@FeignClient注解的name属性改变这个整体的名字。

SpringCloud能让你通过额外的声明配置,来完全控制feign客户端。例如:

@FeignClient(name = "stores", configuration = FooConfiguration.class)
public interface StoreClient {
    //..
}

在这种情况下,客户端是由FeignClientsConfiguration中已经存在的组件和FooConfiguration中的任何组件(其中后者将覆盖前者)组成的。

注意:FooConfiguration不需要使用@Configuration进行注释。但是,如果用了,那么要注意将它排除在任何可能包含@ComponentScan配置之外,因为它将成为feign中feign.Decoder,feign.Encoder, feign.Contract等的默认源。可以通过将它放在任何@ComponentScan或@SpringBootApplication中单独的、不重叠的包中来避免这种情况,也可以在@ComponentScan中显式地排除它。

以前,使用url属性时不需要name属性。现在需要使用name。属性支持占位符。

@FeignClient(name = "${feign.name}", url = "${feign.url}")
public interface StoreClient {
    //..
}

Spring Cloud Netflix 为Feign提供了以下beans(BeanType 的bean名称是 class名):

  • Decoder ,feignDecoder:ResponseEntityDecoder(包装了一个SpringDecoder)
  • Encoder, feignEncoder: SpringEncoder
  • Logger,feignLogger:Slf4jLogger
  • Contract,feignContract: SpringMvcContract
  • Feign.Builder,feignBuilder:HystrixFeign.Builder
  • Client,feignClient:如果Ribbon在类路径中,并且启用了它,那么它就是LoadBalancerFeignClient,否则,如果Spring Cloud LoadBalancer在类路径中,那么就使用FeignBlockingLoadBalancerClient。如果它们都不在类路径中,则使用默认的feign客户端。

注意:spring-cloud-starter-openfeign包括了spring-cloud-starter-netflix-ribbonspring-cloud-starter-loadbalancer

OkHttpClient 和 ApacheHttpClient 的Feign客户端可以通过各自的配置项feign.okhttp.enabledfeign.httpclient.enabled设为true,并将它们放在类路劲中,来使用。你可以定制Http客户端,当你使用Apache时使用org.apache.http.impl.client.CloseableHttpClient,当你使用OK HTTP 时,使用okhttp3.OkHttpClient。

Spring Cloud Netflix 没有提供下列feign默认的bean,但还是从应用程序上下文中查找这些bean来创建Feign客户端:

  • Logger.Level
  • Retryer
  • ErrorDecoder
  • Request.Options
  • Collection<RequestInterceptor>
  • SetterFactory
  • QueryMapEncoder

创建一个那些类型之一的bean,并用@FeignClient替代配置,允许你重写任意一个已经声明的bean。例如:

@Configuration
public class FooConfiguration {
    @Bean
    public Contract feignContract() {
        return new feign.Contract.Default();
    }

    @Bean
    public BasicAuthRequestInterceptor basicAuthRequestInterceptor() {
        return new BasicAuthRequestInterceptor("user", "password");
    }
}

这个例子中使用feign.Contract.Default替换了SpringMvcContract,并添加了一个RequestInterceptorRequestInterceptor的集合中。

@FeignClient也可以使用配置文件配置。

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

可以在@EnableFeignClients的属性defaultConfiguration中相似的方式改动默认配置。其中的不同之处,是用改动@EnableFeignClients属性的方式配置,那么改动的配置将应用于所有Feign客户端。

如果你更喜欢用配置文件来配置所有的@FeignClient,你可以创建一个名为default的feign配置(application.yml):

feign:
  client:
    config:
      default:
        connectTimeout: 5000
        readTimeout: 5000
        loggerLevel: basic

如果我们同时使用@Configuration和配置文件,会优先使用配置文件的内容,系统将覆盖@Configuration中的值。如果你希望@Configuration拥有更高优先级,你可以把配置文件中的feign.client.default-to-properties设置为false。

注意:如果您需要在您的RequestInterceptor中使用ThreadLocal绑定变量,那么您需要将Hystrix的线程隔离策略设置为‘SEMAPHORE’,或者在Feign中禁用Hystrix(application.yml):

# To disable Hystrix in Feign
feign:
  hystrix:
    enabled: false

# To set thread isolation to SEMAPHORE
hystrix:
  command:
    default:
      execution:
        isolation:
          strategy: SEMAPHORE

如果我们要使用相同的名字或url来创建多个feign客户端,那么它们需要指向相同的服务,但每一个都要有不同的个性化配置,这时候我们要使用@FeignClientcontextId属性,来避免这些配置bean的名称冲突。

@FeignClient(contextId = "fooClient", name = "stores", configuration = FooConfiguration.class)
public interface FooClient {
    //..
}
@FeignClient(contextId = "barClient", name = "stores", configuration = BarConfiguration.class)
public interface BarClient {
    //..
}

1.3 手动创建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, "https://PROD-SVC");

        this.adminClient = Feign.builder().client(client)
                .encoder(encoder)
                .decoder(decoder)
                .contract(contract)
                .requestInterceptor(new BasicAuthRequestInterceptor("admin", "admin"))
                .target(FooClient.class, "https://PROD-SVC");
    }
}

注意:在上面例子中的FeignClientsConfiguration.class是Spring Cloud Netflix提供的默认配置。PROD-SVC是客户端服务的名称,将标记出请求去到哪里。Feign的Contract对象定义接口上有效的注解和值。自动注入Contract的bean提供了SpringMVC 支持,以取代默认的Feign本地注解。

1.4 Feign Hystrix 支持

如果Hystrix在类路径中,且feign.hystrix.enabled=true,Feign会将所有方法用断路器包裹起来。还可以返回com.netflix.hystrix.HystrixCommand。这允许您使用响应模式(通过调用. toobservable().observe()或异步使用(通过调用.queue())。

要在每个客户端基础上禁用Hystrix支持,请创建一个具有“prototype”scope的Feign.Builder,例如:

@Configuration
public class FooConfiguration {
    @Bean
    @Scope("prototype")
    public Feign.Builder feignBuilder() {
        return Feign.builder();
    }
}

注意:在Spring Cloud Dalston发布之前,如果Hystrix在类路径上,那么在默认情况下,Feign会将所有方法封装在一个断路器中。在Spring Cloud Dalston中更改了此默认行为,以支持选择进入方法。

1.5 Feign Hystrix Fallbacks

Hystrix支持fallback的概念:当电路断开或出现错误时执行的默认代码。要为给定的@FeignClient启用fallback,请将fallback属性设置为实现fallback的类名。您还需要将实现声明为Spring bean。

@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");
    }
}

如果需要访问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());
            }
        };
    }
}

注意:在Feign中fallback的实现和Hystrix fallback的工作方式有一定的局限性。当前fallbakcs并不支持返回值为com.netflix.hystrix.HystrixCommandrx.Observable的方法。

1.6 Feign 和 @Primary

当开启Hystrix fallbacks使用Feign,有多个bean在ApplicationContext中是相同类型的。这会造成@Autowired不起作用,因为这里不只找到一个bean对象,或者没有一个被标记为主要的。Spring Cloud Netflix标记了所有的Feign接口为@Primary来解决这个问题,所以Spring Framework将会知道那个bean应该注入。有时候,这可能不合理。可以在@FeignClient上设置primary=false属性关掉这个习惯。

@FeignClient(name = "hello", primary = false)
public interface HelloClient {
    // methods here
}

1.7 Feign 继承支持

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 {

}

UserController.java

package project.user;

@FeignClient("users")
public interface UserClient extends UserService {

}

注意:通常不建议在服务器和客户端之间共享接口。它引入了紧密耦合,而且在当前的形式下,它实际上也不能与Spring MVC一起工作(方法参数映射不是继承的)。

1.8 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

这些属性允许您选择压缩媒体类型和最小请求阈值长度。

对于除OkHttpClient外的http客户端,可以启用默认的gzip解码器对gzip响应进行UTF-8编码解码:

feign.compression.response.enabled=true
feign.compression.response.useGzipDecoder=true

1.9 Feign 日志

将为创建的每个Feign客户端创建一个日志程序。默认情况下,日志程序的名称是用于创建Feign客户端的接口的完整类名。Feign日志只对DEBUG级别有响应。

application.yml

logging.level.project.user.UserClient: DEBUG

你可能要为每个客户端配置Logger.Level对象,来告诉Feign要记录多少日志。选项有:

  • NONE,不记录日志,默认。
  • BASIC,只记录请求方法和URL以及响应状态代码和执行时间。
  • HEADERS,记录基本信息以及请求和响应标头。
  • FULL,记录请求和响应的标题、正文和元数据。

下面就是将Logger.Level设置为FULL的例子:

@Configuration
public class FooConfiguration {
    @Bean
    Logger.Level feignLoggerLevel() {
        return Logger.Level.FULL;
    }
}

1.10 Feign @QueryMap 支持

OpenFeign的@QueryMap注解提供了将POJO作为GET请求参数的支持。不幸的是,默认的OpenFeign QueryMap注释与Spring不兼容,因为它缺少value属性。

Spring Cloud OpenFeign提供了一个等价的@SpringQueryMap注释,用于将POJO或Map参数注释为查询参数映射。

// Params.java
public class Params {
    private String param1;
    private String param2;

    // [Getters and setters omitted for brevity]
}

下面的feign客户端通过使用@SpringQueryMap注释来使用Params类:

@FeignClient("demo")
public interface DemoTemplate {

    @GetMapping(path = "/demo")
    String demoEndpoint(@SpringQueryMap Params params);
}

如果您需要对生成的查询参数映射有更多的控制,您可以实现一个定制的QueryMapEncoder bean。

1.11 HATEOAS的支持

Spring提供了一些api来创建遵循HATEOAS原则、Spring HATEOAS和Spring Data REST的REST表示。

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值