聲明性REST客戶端:Feign

Feign是一個(gè)聲明式的Web服務(wù)客戶端。這使得Web服務(wù)客戶端的寫入更加方便 要使用Feign創(chuàng)建一個(gè)界面并對(duì)其進(jìn)行注釋。它具有可插入注釋支持,包括Feign注釋和JAX-RS注釋。Feign還支持可插拔編碼器和解碼器。Spring Cloud增加了對(duì)Spring MVC注釋的支持,并使用Spring Web中默認(rèn)使用的HttpMessageConverters。Spring Cloud集成Ribbon和Eureka以在使用Feign時(shí)提供負(fù)載均衡的http客戶端。

如何加入Feign

要在您的項(xiàng)目中包含F(xiàn)eign,請(qǐng)使用組org.springframework.cloud和工件IDspring-cloud-starter-feign的啟動(dòng)器。有關(guān)使用當(dāng)前的Spring Cloud發(fā)布列表設(shè)置構(gòu)建系統(tǒng)的詳細(xì)信息,請(qǐng)參閱Spring Cloud項(xiàng)目頁面。

示例spring boot應(yīng)用

@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值(以上“存儲(chǔ)”)是一個(gè)任意的客戶端名稱,用于創(chuàng)建Ribbon負(fù)載平衡器(有關(guān)Ribbon支持的詳細(xì)信息,請(qǐng)參閱下文))。您還可以使用url屬性(絕對(duì)值或只是主機(jī)名)指定URL。應(yīng)用程序上下文中的bean的名稱是該接口的完全限定名稱。要指定您自己的別名值,您可以使用@FeignClient注釋的qualifier值。

以上的Ribbon客戶端將會(huì)發(fā)現(xiàn)“商店”服務(wù)的物理地址。如果您的應(yīng)用程序是Eureka客戶端,那么它將解析Eureka服務(wù)注冊(cè)表中的服務(wù)。如果您不想使用Eureka,您可以簡(jiǎn)單地配置外部配置中的服務(wù)器列表(例如,參見

上文)。

覆蓋Feign默認(rèn)值

Spring Cloud的Feign支持的中心概念是指定的客戶端。每個(gè)假裝客戶端都是組合的組件的一部分,它們一起工作以根據(jù)需要聯(lián)系遠(yuǎn)程服務(wù)器,并且該集合具有您將其作為應(yīng)用程序開發(fā)人員使用@FeignClient注釋的名稱。Spring Cloud根據(jù)需要,使用FeignClientsConfiguration為每個(gè)已命名的客戶端創(chuàng)建一個(gè)新的集合ApplicationContext。這包含(除其他外)feign.Decoder,feign.Encoder和feign.Contract。

Spring Cloud可以通過使用@FeignClient聲明額外的配置(FeignClientsConfiguration)來完全控制假客戶端。例:

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

public interface StoreClient {

? ? //..

}

在這種情況下,客戶端由FeignClientsConfiguration中的組件與FooConfiguration中的任何組件組成(后者將覆蓋前者)。

注意FooConfiguration不需要使用@Configuration注釋。但是,如果是,則請(qǐng)注意將其從任何@ComponentScan中排除,否則將包含此配置,因?yàn)樗鼘⒊蔀閒eign.Decoder,feign.Encoder,feign.Contract等的默認(rèn)來源,指定時(shí)。這可以通過將其放置在任何@ComponentScan或@SpringBootApplication的單獨(dú)的不重疊的包中,或者可以在@ComponentScan中明確排除。

注意serviceId屬性現(xiàn)在已被棄用,有利于name屬性。

警告以前,使用url屬性,不需要name屬性。現(xiàn)在需要使用name。

name和url屬性支持占位符。

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

public interface StoreClient {

? ? //..

}

Spring Cloud Netflix默認(rèn)為feign(BeanTypebeanName:ClassName)提供以下bean:

DecoderfeignDecoder:ResponseEntityDecoder(其中包含SpringDecoder)

EncoderfeignEncoder:SpringEncoder

LoggerfeignLogger:Slf4jLogger

ContractfeignContract:SpringMvcContract

Feign.BuilderfeignBuilder:HystrixFeign.Builder

ClientfeignClient:如果Ribbon啟用,則為L(zhǎng)oadBalancerFeignClient,否則將使用默認(rèn)的feign客戶端。

可以通過將feign.okhttp.enabled或feign.httpclient.enabled設(shè)置為true,并將它們放在類路徑上來使用OkHttpClient和ApacheHttpClient feign客戶端。

Spring Cloud Netflix 默認(rèn)情況下提供以下bean,但是仍然從應(yīng)用程序上下文中查找這些類型的bean以創(chuàng)建假客戶機(jī):

Logger.Level

Retryer

ErrorDecoder

Request.Options

Collection<RequestInterceptor>

SetterFactory

創(chuàng)建一個(gè)類型的bean并將其放置在@FeignClient配置(例如上面的FooConfiguration)中)允許您覆蓋所描述的每個(gè)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中以與上述相似的方式指定默認(rèn)配置。不同之處在于,此配置將適用于所有假客戶端。

注意如果您需要在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

手動(dòng)創(chuàng)建Feign客戶端

在某些情況下,可能需要以上述方法不可能自定義您的Feign客戶端。在這種情況下,您可以使用Feign Builder API創(chuàng)建客戶端

。下面是一個(gè)創(chuàng)建兩個(gè)具有相同接口的Feign客戶端的示例,但是使用單獨(dú)的請(qǐng)求攔截器配置每個(gè)客戶端。

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

? ? }

}

注意在上面的例子中,F(xiàn)eignClientsConfiguration.class是Spring Cloud Netflix提供的默認(rèn)配置。

注意PROD-SVC是客戶端將要求的服務(wù)的名稱。

Feign Hystrix支持

如果Hystrix在類路徑上,feign.hystrix.enabled=true,F(xiàn)eign將用斷路器包裝所有方法。還可以返回com.netflix.hystrix.HystrixCommand。這樣就可以使用無效模式(調(diào)用.toObservable()或.observe()或異步使用(調(diào)用.queue()))。

要在每個(gè)客戶端基礎(chǔ)上禁用Hystrix支持創(chuàng)建一個(gè)帶有“原型”范圍的香草Feign.Builder,例如:

@Configuration

public class FooConfiguration {

? ? @Bean

@Scope("prototype")

public Feign.Builder feignBuilder() {

return Feign.builder();

}

}

警告在Spring Cloud達(dá)爾斯頓發(fā)布之前,如果Hystrix在類路徑Feign中默認(rèn)將所有方法包裝在斷路器中。這種默認(rèn)行為在Spring Cloud達(dá)爾斯頓改變了贊成選擇加入的方式。

Feign Hystrix回退

Hystrix支持回退的概念:當(dāng)電路斷開或出現(xiàn)錯(cuò)誤時(shí)執(zhí)行的默認(rèn)代碼路徑。要為給定的@FeignClient啟用回退,請(qǐng)將fallback屬性設(shè)置為實(shí)現(xiàn)回退的類名。

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

? ? }

}

如果需要訪問導(dǎo)致回退觸發(fā)的原因,可以使用@FeignClient內(nèi)的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中執(zhí)行回退以及Hystrix回退的工作方式存在局限性。當(dāng)前返回com.netflix.hystrix.HystrixCommand和rx.Observable的方法目前不支持回退。

Feign和@Primary

當(dāng)使用Feign與Hystrix回退時(shí),在同一類型的ApplicationContext中有多個(gè)bean。這將導(dǎo)致@Autowired不起作用,因?yàn)闆]有一個(gè)bean,或者標(biāo)記為主。要解決這個(gè)問題,Spring Cloud Netflix將所有Feign實(shí)例標(biāo)記為@Primary,所以Spring Framework將知道要注入哪個(gè)bean。在某些情況下,這可能是不可取的。要關(guān)閉此行為,將@FeignClient的primary屬性設(shè)置為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 {

}

注意通常不建議在服務(wù)器和客戶端之間共享接口。它引入了緊耦合,并且實(shí)際上并不適用于當(dāng)前形式的Spring MVC(方法參數(shù)映射不被繼承)。

Feign請(qǐng)求/響應(yīng)壓縮

您可以考慮為Feign請(qǐng)求啟用請(qǐng)求或響應(yīng)GZIP壓縮。您可以通過啟用其中一個(gè)屬性來執(zhí)行此操作:

feign.compression.request.enabled=true

feign.compression.response.enabled=true

Feign請(qǐng)求壓縮為您提供與您為Web服務(wù)器設(shè)置的設(shè)置相似的設(shè)置:

feign.compression.request.enabled=true

feign.compression.request.mime-types=text/xml,application/xml,application/json

feign.compression.request.min-request-size=2048

這些屬性可以讓您對(duì)壓縮介質(zhì)類型和最小請(qǐng)求閾值長(zhǎng)度有選擇性。

Feign日志記錄

為每個(gè)創(chuàng)建的Feign客戶端創(chuàng)建一個(gè)記錄器。默認(rèn)情況下,記錄器的名稱是用于創(chuàng)建Feign客戶端的接口的完整類名。Feign日志記錄僅響應(yīng)DEBUG級(jí)別。

application.yml

logging.level.project.user.UserClient: DEBUG

您可以為每個(gè)客戶端配置的Logger.Level對(duì)象告訴Feign記錄多少。選擇是:

NONE,無記錄(DEFAULT)。

BASIC,只記錄請(qǐng)求方法和URL以及響應(yīng)狀態(tài)代碼和執(zhí)行時(shí)間。

HEADERS,記錄基本信息以及請(qǐng)求和響應(yīng)標(biāo)頭。

FULL,記錄請(qǐng)求和響應(yīng)的頭文件,正文和元數(shù)據(jù)。

例如,以下將Logger.Level設(shè)置為FULL:

@Configuration

public class FooConfiguration {

? ? @Bean

? ? Logger.Level feignLoggerLevel() {

? ? ? ? return Logger.Level.FULL;

? ? }

}

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

推薦閱讀更多精彩內(nèi)容

  • Feign是一個(gè)聲明式的Web服務(wù)客戶端。這使得Web服務(wù)客戶端的寫入更加方便 要使用Feign創(chuàng)建一個(gè)界面并對(duì)其...
    咔啡閱讀 183評(píng)論 0 1
  • Feign是一個(gè)聲明式的Web服務(wù)客戶端。這使得Web服務(wù)客戶端的寫入更加方便 要使用Feign創(chuàng)建一個(gè)界面并對(duì)其...
    咔啡閱讀 186評(píng)論 0 1
  • 聲明式Web服務(wù)客戶端。寫入更方便,F(xiàn)eign創(chuàng)建界面并其注釋??刹迦胱⑨屩С?,F(xiàn)eign注釋和JAX-RS注釋。...
    hedgehog1112閱讀 686評(píng)論 0 0
  • 1.Feign介紹 Feign是一個(gè)聲明式的Web服務(wù)客戶端。這使得Web服務(wù)客戶端的寫入更加方便 要使用Feig...
    金角大王的爺爺閱讀 684評(píng)論 0 0
  • 回想大學(xué)期間,被盜之自行車共約五輛,不可謂不多,為此,還曾給小偷寫過一封信,摘錄如下。 敬愛的小偷先生: 強(qiáng)壓住心...
    LCL龍華閱讀 220評(píng)論 0 0