[Spring Cloud] 4.6 Declarative REST Client:Feign

4.6 Declarative REST Client: Feign

REST客戶端:Feign

Feign是一個Web服務的客戶端框架。它讓Web服務的客戶端開發變得更容易。 只須要使用Feign建立一個接口加上一個註解就好了。Feign和JAX-RS提供一整套插件化的註解配置方式。在Feign中還可使用插件化的編碼器和解碼器。java

Spring Cloud 還提供一個HttpMessageConverters,這樣當使用Spring Web環境時,就能夠支持Spring MVC。 在使用Feign時,Spring Cloud還能夠整合Ribbon和Eureka,爲http客戶端提供負載均衡的能力。git

4.6.1 How to Include Feign 如何引入Feign

在工程中引入Feign只須要引入依賴就行:group :org.springframework.cloud artifact id : spring-cloud-starter-feign。詳情見Spring Cloud相關文檔github

例如:web

@Configuration
@ComponentScan
@EnableAutoConfiguration
@EnableEurekaClient
@EnableFeignClients
public class Application {

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

}

StoreClient.javaspring

@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負載均衡器。 還能夠配置url屬性來指定URL。 在Spring容器中會使用全限定名做爲這個Bean的名稱。一樣,能夠經過name屬性進行自定義。 在上例中,經過@Qualifier("storesFeignClient")就能夠引用到這個Bean。 若是須要改變默認引用名稱,能夠在@FeignClient中配置qualifier屬性。apache

Ribbon客戶端將會查找"stores"服務的物理地址。 若是是一個Eureka客戶端應用,那麼將會自動註冊到Eureka中。 若是不想使用Eureka,能夠簡單的配置一個服務列表,手動指定服務。json

4.6.2 Overriding Feign Defaults 覆蓋Feign默認配置

Spring Cloud 的 Feign有一個核心概念,那就是客戶端命名。每個Feign客戶端都是集羣中一組@FeignClient標記的可用服務區域中的一部分。app

Spring Cloud會爲每個命名的Feign客戶端中的FeignClientsConfiguration建立一個新的ApplicationContext。 這其中會包括一個feign.Decoder,一個feign.Encoder,以及一個feign.Contract負載均衡

Spring Cloud運行開發者經過@FeignClient對Feign客戶端進行徹底的控制。例如:框架

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

在這個例子中,客戶端使用一個自定義的FooConfiguration整合到FeignClientsConfiguration的配置過程。

警告:

須要確保FooConfiguration不會被@Configuration或者@ComponentScan掃描到,不然,就會被全部@FeignClient共享了(自動注入)。若是使用@ComponentScan或者@SpringBootApplication時,也須要避免FooConfiguration被自動掃描。

注意:

serviceId屬性已經丟棄,不建議使用,改用name屬性進行配置。

警告:

之前使用url屬性時,不須要name。如今不行了,name必須指定。

nameurl屬性時,可使用佔位符進行配置。例如:

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

Spring Cloud Netflix 默認會建立下列Bean

類型 Bean名稱 類名 備註
Decoder feignDecoder ResponseEntityDecoder 包裝了SpringDecoder
Encoder feignEncoder SpringEncoder
Logger feignLogger Slf4jLogger
Contract feignContract SpringMvcContract
Feign.Builder feignBuilder HystrixFeign.Builder
Client feignClient LoadBalancerFeignClient 若是啓用Ribbon則是LoadBalancerFeignClient,不然使用Feign默認客戶端

還能夠經過feign.okhttp.enabled或者feign.httpclient.enabled來開啓OkHttpClientApacheHttpClient,固然前提是classpath中必須有這些相關依賴。

默認狀況下,Spring Cloud Netflix不會爲Feign提供下列的Bean,可是仍然能夠在spring上下文中經過類型找到它們來建立Feign客戶端。

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

能夠在@FeignClient的配置類中,自行建立這些Bean來訂製Feign客戶端。例如:

@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,同時加上一個RequestInterceptor

默認配置能夠經過@EnableFeignClientsdefaultConfiguration屬性來制定。這些配置,會被應用到全部的Feign客戶端上。

4.6.3 Creating Feign Clients Manually 手動建立Feign客戶端

在某些場景中,經過上述方法,仍是不能獲得一個想要的Feign客戶端。 那這個時候,就須要本身經過Feign Builder API來手動建立客戶端。 下面這個例子就展示了爲同一個接口建立兩個不一樣配置的客戶端。

@Import(FeignClientsConfiguration.class)
class FooController {

	private FooClient fooClient;

	private FooClient adminClient;

    @Autowired
	public FooController(
			ResponseEntityDecoder decoder, SpringEncoder 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是服務的客戶端請求時標記的名稱。

4.6.4 Feign Hystrix Support :Feign斷路器

若是在classpath中加入了Hystrix,那默認Feign就會爲全部方法都包裝上一個斷路器。也會返回一個com.netflix.hystrix.HystrixCommand。這就會致使可使用正則匹配(如:調用.toObservable() or .observe())或者異步請求(如:調用.queue())。

若是不想在Feign使用Hystrix,能夠配置:feign.hystrix.enabled=false

若是想讓每一個客戶端都不使用Hystrix,能夠在prototype做用域中建立一個普通的Feign.Builder實現。例如:

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

4.6.5 Feign Hystrix Fallbacks : Feign降級

Hystrix中的降級概念:當鏈路中發生錯誤是,執行一個默認的代碼邏輯。 能夠在@FeignClient中配置fallback屬性,來開啓Feign降級處理。例如:

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

若是想在降級操做中處理拋出的異常,可使用@FeignClientfallbackFactory屬性。例如:

@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

4.6.6 Feign Inheritance Support 繼承

Feign只支持接口層的單繼承。能夠將一些通用操做抽象成一個基礎接口。例如:

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版本中也不支持這種方式(共用接口)。

4.6.7 Feign request/response compression 數據壓縮

能夠考慮對Feign的request和response開啓GZIP壓縮處理。能夠在配置文件中經過以下配置開啓:

feign.compression.request.enabled=true
feign.compression.response.enabled=true

在web服務中進行更詳細的配置:

feign.compression.request.enabled=true
feign.compression.request.mime-types=text/xml,application/xml,application/json
feign.compression.request.min-request-size=2048

上例中,指定了Media type和壓縮的最小大小進行了指定。

4.6.8 Feign logging 日誌

對於建立的每一個Feign客戶端都會建立一個Logger。默認狀況下,使用客戶端全類名做爲日誌名,Feign日誌只能設置爲DEBUG級別。

application.yml

logging.level.project.user.UserClient: DEBUG

能夠爲每一個客戶端配置一個Logger.Level對象,來告訴Feign如何輸出日誌。能夠選擇如下級別:

  • NONE,無日誌(默認
  • BASIC,僅輸出請求的方法、URL、response status code 以及執行時間
  • HEADERS,帶上request和response的header信息
  • FULL,包括requset和response的header,body以及元數據

例如:

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

4.7 External Configuration: Archaius 使用Archaius進行外部擴展配置

Archaius是一個Netflix客戶端配置的類庫。這個類庫能夠被用於全部的Netflix OSS組件的配置。Archaius是在Apache Commons Configuration的基礎山進行擴展出來的。Archaius容許客戶端輪詢自動發現配置的改動變化。Archaius經過Dynamic<Type>Property類來處理各類配置屬性。

Archaius Example

class ArchaiusTest {
    DynamicStringProperty myprop = DynamicPropertyFactory
            .getInstance()
            .getStringProperty("my.prop");

    void doSomething() {
        OtherClass.someMethod(myprop.get());
    }
}

Archaius有本身的配置文件集以及預先加載機制。Spring應用一般不會直接使用Archaius,而是經過Netflix原生的配置工具進行使用。Spring Cloud提供一個Spring Environment來對Archaius屬性進行橋接使用。這樣就可讓Spring Boot應用能像使用普通配置屬性同樣使用Archaius。

相關文章
相關標籤/搜索