声明性REST客户端:Feign

Feign是一个声明式的Web服务客户端。这使得Web服务客户端的写入更加方便 要使用Feign创建一个界面并对其进行注释。它具有可插入注释支持,包括Feign注释和JAX-RS注释。Feign还支持可插拔编码器和解码器。Spring Cloud增加了对Spring MVC注释的支持,并使用Spring Web中默认使用的HttpMessageConverters。Spring Cloud集成Ribbon和Eureka以在使用Feign时提供负载均衡的http客户端。

如何加入Feign

要在您的项目中包含Feign,请使用组org.springframework.cloud和工件IDspring-cloud-starter-feign的启动器。有关使用当前的Spring Cloud发布列表设置构建系统的详细信息,请参阅Spring Cloud项目页面

示例spring boot应用

@Configuration

@ComponentScan

@EnableAutoConfiguration

@EnableEurekaClient

@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注释中,String值(以上“存储”)是一个任意的客户端名称,用于创建Ribbon负载平衡器(有关Ribbon支持的详细信息,请参阅下文))。您还可以使用url属性(绝对值或只是主机名)指定URL。应用程序上下文中的bean的名称是该接口的完全限定名称。要指定您自己的别名值,您可以使用@FeignClient注释的qualifier值。

以上的Ribbon客户端将会发现“商店”服务的物理地址。如果您的应用程序是Eureka客户端,那么它将解析Eureka服务注册表中的服务。如果您不想使用Eureka,您可以简单地配置外部配置中的服务器列表(例如,参见

上文)。

覆盖Feign默认值

Spring Cloud的Feign支持的中心概念是指定的客户端。每个假装客户端都是组合的组件的一部分,它们一起工作以根据需要联系远程服务器,并且该集合具有您将其作为应用程序开发人员使用@FeignClient注释的名称。Spring Cloud根据需要,使用FeignClientsConfiguration为每个已命名的客户端创建一个新的集合ApplicationContext。这包含(除其他外)feign.Decoder,feign.Encoder和feign.Contract。

Spring Cloud可以通过使用@FeignClient声明额外的配置(FeignClientsConfiguration)来完全控制假客户端。例:

@FeignClient(name = "stores", configuration = FooConfiguration.class)

public interface StoreClient {

    //..

}

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

注意FooConfiguration不需要使用@Configuration注释。但是,如果是,则请注意将其从任何@ComponentScan中排除,否则将包含此配置,因为它将成为feign.Decoder,feign.Encoder,feign.Contract等的默认来源,指定时。这可以通过将其放置在任何@ComponentScan或@SpringBootApplication的单独的不重叠的包中,或者可以在@ComponentScan中明确排除。

注意serviceId属性现在已被弃用,有利于name属性。

警告以前,使用url属性,不需要name属性。现在需要使用name。

name和url属性支持占位符。

@FeignClient(name = "${feign.name}", url = "${feign.url}")

public interface StoreClient {

    //..

}

Spring Cloud Netflix默认为feign(BeanTypebeanName:ClassName)提供以下bean:

DecoderfeignDecoder:ResponseEntityDecoder(其中包含SpringDecoder)

EncoderfeignEncoder:SpringEncoder

LoggerfeignLogger:Slf4jLogger

ContractfeignContract:SpringMvcContract

Feign.BuilderfeignBuilder:HystrixFeign.Builder

ClientfeignClient:如果Ribbon启用,则为LoadBalancerFeignClient,否则将使用默认的feign客户端。

可以通过将feign.okhttp.enabled或feign.httpclient.enabled设置为true,并将它们放在类路径上来使用OkHttpClient和ApacheHttpClient feign客户端。

Spring Cloud Netflix 默认情况下提供以下bean,但是仍然从应用程序上下文中查找这些类型的bean以创建假客户机:

Logger.Level

Retryer

ErrorDecoder

Request.Options

Collection<RequestInterceptor>

SetterFactory

创建一个类型的bean并将其放置在@FeignClient配置(例如上面的FooConfiguration)中)允许您覆盖所描述的每个bean。例:

@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,并将RequestInterceptor添加到RequestInterceptor的集合中。

可以在@EnableFeignClients属性defaultConfiguration中以与上述相似的方式指定默认配置。不同之处在于,此配置将适用于所有假客户端。

注意如果您需要在RequestInterceptor`s you will need to either set the

thread isolation strategy for Hystrix to `SEMAPHORE中使用ThreadLocal绑定变量,或在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

手动创建Feign客户端

在某些情况下,可能需要以上述方法不可能自定义您的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) {

this.fooClient = Feign.builder().client(client)

.encoder(encoder)

.decoder(decoder)

.requestInterceptor(new BasicAuthRequestInterceptor("user", "user"))

.target(FooClient.class, "http://PROD-SVC");

this.adminClient = Feign.builder().client(client)

.encoder(encoder)

.decoder(decoder)

.requestInterceptor(new BasicAuthRequestInterceptor("admin", "admin"))

.target(FooClient.class, "http://PROD-SVC");

    }

}

注意在上面的例子中,FeignClientsConfiguration.class是Spring Cloud Netflix提供的默认配置。

注意PROD-SVC是客户端将要求的服务的名称。

Feign Hystrix支持

如果Hystrix在类路径上,feign.hystrix.enabled=true,Feign将用断路器包装所有方法。还可以返回com.netflix.hystrix.HystrixCommand。这样就可以使用无效模式(调用.toObservable()或.observe()或异步使用(调用.queue()))。

要在每个客户端基础上禁用Hystrix支持创建一个带有“原型”范围的香草Feign.Builder,例如:

@Configuration

public class FooConfiguration {

    @Bean

@Scope("prototype")

public Feign.Builder feignBuilder() {

return Feign.builder();

}

}

警告在Spring Cloud达尔斯顿发布之前,如果Hystrix在类路径Feign中默认将所有方法包装在断路器中。这种默认行为在Spring Cloud达尔斯顿改变了赞成选择加入的方式。

Feign Hystrix回退

Hystrix支持回退的概念:当电路断开或出现错误时执行的默认代码路径。要为给定的@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 HystrixClientWithFallBackFactory() {

@Override

public Hello iFailSometimes() {

return new Hello("fallback; reason was: " + cause.getMessage());

}

};

}

}

警告在Feign中执行回退以及Hystrix回退的工作方式存在局限性。当前返回com.netflix.hystrix.HystrixCommand和rx.Observable的方法目前不支持回退。

Feign和@Primary

当使用Feign与Hystrix回退时,在同一类型的ApplicationContext中有多个bean。这将导致@Autowired不起作用,因为没有一个bean,或者标记为主。要解决这个问题,Spring Cloud Netflix将所有Feign实例标记为@Primary,所以Spring Framework将知道要注入哪个bean。在某些情况下,这可能是不可取的。要关闭此行为,将@FeignClient的primary属性设置为false。

@FeignClient(name = "hello", primary = false)

public interface HelloClient {

// methods here

}

Feign继承支持

Feign通过单继承接口支持样板apis。这样就可以将常用操作分成方便的基本界面。

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 {

}

注意通常不建议在服务器和客户端之间共享接口。它引入了紧耦合,并且实际上并不适用于当前形式的Spring MVC(方法参数映射不被继承)。

Feign请求/响应压缩

您可以考虑为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客户端的接口的完整类名。Feign日志记录仅响应DEBUG级别。

application.yml

logging.level.project.user.UserClient: DEBUG

您可以为每个客户端配置的Logger.Level对象告诉Feign记录多少。选择是:

NONE,无记录(DEFAULT)。

BASIC,只记录请求方法和URL以及响应状态代码和执行时间。

HEADERS,记录基本信息以及请求和响应标头。

FULL,记录请求和响应的头文件,正文和元数据。

例如,以下将Logger.Level设置为FULL:

@Configuration

public class FooConfiguration {

    @Bean

    Logger.Level feignLoggerLevel() {

        return Logger.Level.FULL;

    }

}

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,242评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,769评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,484评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,133评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,007评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,080评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,496评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,190评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,464评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,549评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,330评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,205评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,567评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,889评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,160评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,475评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,650评论 2 335

推荐阅读更多精彩内容