1. 程式人生 > >Spring Cloud Feign REST客戶端

Spring Cloud Feign REST客戶端

宣告性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

和工件ID spring-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.Decoderfeign.Encoderfeign.Contract

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

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

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

注意 FooConfiguration不需要使用@Configuration註釋。但是,如果是,則請注意將其從任何@ComponentScan中排除,否則將包含此配置,因為它將成為feign.Decoderfeign.Encoderfeign.Contract等的預設來源,指定時。這可以通過將其放置在任何@ComponentScan@SpringBootApplication的單獨的不重疊的包中,或者可以在@ComponentScan中明確排除。
注意 serviceId屬性現在已被棄用,有利於name屬性。
警告 以前,使用url屬性,不需要name屬性。現在需要使用name

nameurl屬性支援佔位符。

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

Spring Cloud Netflix預設為feign(BeanType beanName:ClassName)提供以下bean:

  • Decoder feignDecoder:ResponseEntityDecoder(其中包含SpringDecoder

  • Encoder feignEncoder:SpringEncoder

  • Logger feignLogger:Slf4jLogger

  • Contract feignContract:SpringMvcContract

  • Feign.Builder feignBuilder:HystrixFeign.Builder

  • Client feignClient:如果Ribbon啟用,則為LoadBalancerFeignClient,否則將使用預設的feign客戶端。

可以通過將feign.okhttp.enabledfeign.httpclient.enabled設定為true,並將它們放在類路徑上來使用OkHttpClient和ApacheHttpClient feign客戶端。

Spring Cloud Netflix 預設情況下不提供以下bean,但是仍然從應用程式上下文中查詢這些型別的bean以建立假客戶機:

  • Logger.Level

  • Retryer

  • ErrorDecoder

  • Request.Options

  • Collection

  • 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.HystrixCommandrx.Observable的方法目前不支援回退。

Feign和@Primary

當使用Feign與Hystrix回退時,在同一型別的ApplicationContext中有多個bean。這將導致@Autowired不起作用,因為沒有一個bean,或者標記為主。要解決這個問題,Spring Cloud Netflix將所有Feign例項標記為@Primary,所以Spring Framework將知道要注入哪個bean。在某些情況下,這可能是不可取的。要關閉此行為,將@FeignClientprimary屬性設定為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;
    }
}

歡迎關注作者的公眾號《Java程式設計生活》,每日記載Java程式猿工作中遇到的問題 在這裡插入圖片描述