官方文檔地址為:http://cloud.spring.io/spring-cloud-static/Dalston.SR2/#spring-cloud-feign
文中例子我做了一些測試在:http://git.oschina.net/dreamingodd/spring-cloud-preparation
Declarative REST Client: Feign 聲明式Rest客戶端:Feign
Feign is a declarative web service client. It makes writing web service clients easier. To use Feign create an interface and annotate it. It has pluggable annotation support including Feign annotations and JAX-RS annotations. Feign also supports pluggable encoders and decoders. Spring Cloud adds support for Spring MVC annotations and for using the same HttpMessageConverters used by default in Spring Web. Spring Cloud integrates Ribbon and Eureka to provide a load balanced http client when using Feign.
Feigh是一個聲明式web服務客戶端。它能讓開發web服務變得容易。使用Feign需要創建一個接口並注解它。它擁有包括Feign注解和JAX-RS注解的可插拔支持。它還支持可插拔的編碼器和解碼器。Spring Cloud擁有Spring MVC支持,並使用Spring Web中默認同樣的HttpMessageConverters。在使用Feign時,Spring Cloud集成了Ribbon和Eureka來提供負載均衡的HTTP客戶端。
How to Include Feign
To include Feign in your project use the starter with group org.springframework.cloud and artifact id spring-cloud-starter-feign. See the Spring Cloud Project page for details on setting up your build system with the current Spring Cloud Release Train.
org.springframework.cloud spring-cloud-starter-feign 更多詳細內容請移步Spring Cloud Project。
Example spring boot app
@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); }
In the @FeignClient annotation the String value ("stores" above) is an arbitrary client name, which is used to create a Ribbon load balancer (see below for details of Ribbon support). You can also specify a URL using the url attribute (absolute value or just a hostname). The name of the bean in the application context is the fully qualified name of the interface. To specify your own alias value you can use the qualifier value of the @FeignClient annotation.
@FeignClient注解中的String(也就是上面的“stores”)可以是任意的客戶端名稱,用於創建Ribbon負載均衡器(詳見上文Ribbon supprot)。開發人員亦可使用URL(絕對路徑或主機名)。application上下文中的bean名稱為該接口的全限定名稱。要制定別名的話,開發人員可以用@FeignClient注解的限定名稱。
The Ribbon client above will want to discover the physical addresses for the "stores" service. If your application is a Eureka client then it will resolve the service in the Eureka service registry. If you don’t want to use Eureka, you can simply configure a list of servers in your external configuration (see above for example).
上文中的Ribbon客戶端會嘗試發現“stores”服務的物理地址。如果它是一個Eureka客戶端,那么服務就會再Eureka服務注冊機中注冊。如果不想使用Eureka,開發人員可以在外部配置中簡單配置服務列表。(參見上文)
Overriding Feign Defaults 覆蓋Feign默認行為
A central concept in Spring Cloud’s Feign support is that of the named client. Each feign client is part of an ensemble of components that work together to contact a remote server on demand, and the ensemble has a name that you give it as an application developer using the @FeignClient annotation. Spring Cloud creates a new ensemble as an ApplicationContext on demand for each named client using FeignClientsConfiguration. This contains (amongst other things) an feign.Decoder, a feign.Encoder, and a feign.Contract.
Spring Cloud的Feign支持的核心概念(之一)是命名客戶端。每個Feign客戶端都是組件集合的一部分,它們按需共同工作去鏈接遠程服務器,該集合的名稱由開發人員定義在@FeignClient注解中。Spring Cloud為每個使用FeignClientConfiguration的命名客戶端按需創建ApplicationContext-組件集合。集合包括feign.Decoder,feign.Encoder和feign.Contract。
Spring Cloud lets you take full control of the feign client by declaring additional configuration (on top of the FeignClientsConfiguration) using @FeignClient. Example:
與使用Ribbon時一樣,聲明額外的configuration可以讓Spring Cloud把全部控制權交給開發人員。例如:
@FeignClient(name = "stores", configuration = FooConfiguration.class) public interface StoreClient { //.. }
In this case the client is composed from the components already in FeignClientsConfiguration together with any in FooConfiguration (where the latter will override the former).
本例中,客戶端由已在FeignClientsConfiguration中的組件以及FooConfiguration中的任意組件組成(后者通常覆蓋前者)。
NOTE FooConfiguration does not need to be annotated with @Configuration. However, if it is, then take care to exclude it from any @ComponentScan that would otherwise include this configuration as it will become the default source for feign.Decoder, feign.Encoder, feign.Contract, etc., when specified. This can be avoided by putting it in a separate, non-overlapping package from any @ComponentScan or @SpringBootApplication, or it can be explicitly excluded in @ComponentScan.
注意 FooConfiguration必須有@Configuration,但注意它並不在主應用上下文的@ComponentScan中,否則它會被所有的@RibbonClients分享(意思就是覆蓋所有客戶端的默認值)。如果開發人員使用@ComponentScan(或@SpringBootApplication),那就必須采取措施避免被覆蓋到(例如將其放入一個獨立的,不重疊的包中,或以@ComponentScan指明要掃描的包。
NOTE The serviceId attribute is now deprecated in favor of the name attribute.
注意 ServiceId屬性現已啟用,更多使用name屬性。
WARNING Previously, using the url attribute, did not require the name attribute. Using name is now required.
警告 之前使用URL屬性不需要name屬性。但現在需要了。
Placeholders are supported in the name and url attributes.
Name和URL屬性支持占位符。比如:
@FeignClient(name = "${feign.name}", url = "${feign.url}") public interface StoreClient { //.. }
Spring Cloud Netflix provides the following beans by default for feign (BeanType beanName: ClassName):
Spring Cloud Netflix為feign提供以下默認bean(Bean類型 bean名稱: Class名稱):
- Decoder feignDecoder: ResponseEntityDecoder (which wraps a SpringDecoder)
- Encoder feignEncoder: SpringEncoder
- Logger feignLogger: Slf4jLogger
- Contract feignContract: SpringMvcContract
- Feign.Builder feignBuilder: HystrixFeign.Builder
- Client feignClient: if Ribbon is enabled it is a LoadBalancerFeignClient, otherwise the default feign client is used.
The OkHttpClient and ApacheHttpClient feign clients can be used by setting feign.okhttp.enabled or feign.httpclient.enabled to true, respectively, and having them on the classpath.
要使用OkHttpClient或ApacheHttpClient,需要把feign.okhttp.enabled或feign.httpclient.enabled設置為true並將其放入classpath。
Spring Cloud Netflix does not provide the following beans by default for feign, but still looks up beans of these types from the application context to create the feign client:
Spring Cloud Netflix並不默認提供以下bean,但是創建Feign客戶端時,仍然會去application上下文中尋找這些類型的bean。
- Logger.Level
- Retryer
- ErrorDecoder
- Request.Options
- Collection<RequestInterceptor>
- SetterFactory
Creating a bean of one of those type and placing it in a @FeignClient configuration (such as FooConfiguration above) allows you to override each one of the beans described. Example:
覆蓋上文的bean只需創建並將其放入@FeignClient配置類中(比如上文的FooConfiguration)。實例:
@Configuration public class FooConfiguration { @Bean public Contract feignContract() { return new feign.Contract.Default(); } @Bean public BasicAuthRequestInterceptor basicAuthRequestInterceptor() { return new BasicAuthRequestInterceptor("user", "password"); } }
This replaces the SpringMvcContract with feign.Contract.Default and adds a RequestInterceptor to the collection of RequestInterceptor.
以上代碼用feign.Contract.Default替換了SpringMvcContract,並在RequestInterceptor集合中加入了一個新的。
Default configurations can be specified in the @EnableFeignClients attribute defaultConfiguration in a similar manner as described above. The difference is that this configuration will apply to all feign clients.
與上文描述類似,默認配置可以在@EnableFeignClients屬性默認配置中指定。不同點在於這樣做將會影響所有的feign客戶端。
NOTE If you need to use ThreadLocal bound variables in your RequestInterceptor's you will need to either set the thread isolation strategy for Hystrix to "SEMAPHORE" or disable Hystrix in Feign.
注意 若開發人員需要在RequestInterceptor中使用ThreadLocal變量,則需要將Hystrix的隔離級別設置為“SEMAPHORE”,或直接禁用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
Creating Feign Clients Manually 手動創建Feign客戶端
In some cases it might be necessary to customize your Feign Clients in a way that is not possible using the methods above. In this case you can create Clients using the Feign Builder API. Below is an example which creates two Feign Clients with the same interface but configures each one with a separate request interceptor.
特殊情況下,當上文中的方法不可用的時候,開發人員需要自定義Ribbon客戶端,請參考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"); } }
NOTE In the above example FeignClientsConfiguration.class is the default configuration provided by Spring Cloud Netflix.
注意 上文中的FeignClientsConfiguration.class是Spring Cloud Netflix提供的默認配置。
NOTE PROD-SVC is the name of the service the Clients will be making requests to.
注意 PROD-SVC是客戶端會去請求的服務名。
Feign Hystrix Support Feign的Hystrix支持
If Hystrix is on the classpath and feign.hystrix.enabled=true, Feign will wrap all methods with a circuit breaker. Returning a com.netflix.hystrix.HystrixCommand is also available. This lets you use reactive patterns (with a call to .toObservable() or .observe() or asynchronous use (with a call to .queue()).
如果Hystrix在classpath中並把feign.hystrix.enabled設置為true,那么Feign將用斷路器包裝所有的方法。返回com.netflix.hystrix.HystrixCommand也是可用的。這使開發人員能夠使用反應模式(調用.toObservable()或.observe()或異步使用-調用.queue())
To disable Hystrix support on a per-client basis create a vanilla Feign.Builder with the "prototype" scope, e.g.:
禁用Hystrix支持,要創建有一個帶有“原型”周期的vanilla Feign.Builder。 例如:
@Configuration public class FooConfiguration { @Bean @Scope("prototype") public Feign.Builder feignBuilder() { return Feign.builder(); } }
WARNING Prior to the Spring Cloud Dalston release, if Hystrix was on the classpath Feign would have wrapped all methods in a circuit breaker by default. This default behavior was changed in Spring Cloud Dalston in favor for an opt-in approach.
警告 在Dalston版本之前,Feign + Hystrix默認用斷路器包裝所有方法。Dalston版本改成了選擇進入的方式
Feign Hystrix Fallbacks Feign Hystrix失敗回退
Hystrix supports the notion of a fallback: a default code path that is executed when they circuit is open or there is an error. To enable fallbacks for a given @FeignClient set the fallback attribute to the class name that implements the fallback. You also need to declare your implementation as a Spring bean.
Hystrix支持失敗回退理念:無論斷路器成功還是失敗都會一個默認的代碼路徑。開啟fallback只需給@FeignClient加入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"); } }
If one needs access to the cause that made the fallback trigger, one can use the fallbackFactory attribute inside @FeignClient.
如果需要訪問導致失敗回退觸發的原因,可以使用@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()); } }; } }
WARNING There is a limitation with the implementation of fallbacks in Feign and how Hystrix fallbacks work. Fallbacks are currently not supported for methods that return com.netflix.hystrix.HystrixCommand and rx.Observable.
警告 Feign的實現和Hystrix的失敗回退方式有一個局限性。暫不支持返回com.netflix.hystrix.HystrixCommand and rx.Observable的方法。
Feign and @Primary
When using Feign with Hystrix fallbacks, there are multiple beans in the ApplicationContext of the same type. This will cause @Autowired to not work because there isn’t exactly one bean, or one marked as primary. To work around this, Spring Cloud Netflix marks all Feign instances as @Primary, so Spring Framework will know which bean to inject. In some cases, this may not be desirable. To turn off this behavior set the primary attribute of @FeignClient to false.
使用Hystrix fallbacks時,ApplicationContext中有相同類型的多個bean。導致@Autowired定位不到准確的bean,或標記為@Primary。解決這個問題,Spring Cloud Netflix將所有Feign實例標記為@Primary,這樣Spring框架將會知道要注入哪個bean。在某些情況下,這可能是不可取的。 要關閉此行為,將@FeignClient的主屬性設置為false。
@FeignClient(name = "hello", primary = false) public interface HelloClient { // methods here }
Feign Inheritance Support Feign繼承支持
Feign supports boilerplate apis via single-inheritance interfaces. This allows grouping common operations into convenient base interfaces.
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 { }
UserClient.java
package project.user; @FeignClient("users") public interface UserClient extends UserService { }
NOTE It is generally not advisable to share an interface between a server and a client. It introduces tight coupling, and also actually doesn’t work with Spring MVC in its current form (method parameter mapping is not inherited).
注意 一般不建議講一個接口同時設置為服務端和客戶端。這樣就引入了緊耦合,並且實際上在當前模式下無法和Spring MVC協同工作(方法參數映射不被繼承)。
Feign request/response compression Feign的請求/響應壓縮
You may consider enabling the request or response GZIP compression for your Feign requests. You can do this by enabling one of the properties:
如果考慮壓縮request/response為GZIP,使用以下屬性:
feign.compression.request.enabled=true feign.compression.response.enabled=true
Feign request compression gives you settings similar to what you may set for your web server:
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
These properties allow you to be selective about the compressed media types and minimum request threshold length.
這些屬性可以控制壓縮的媒體類型和最小請求閾值。
Feign logging
A logger is created for each Feign client created. By default the name of the logger is the full class name of the interface used to create the Feign client. Feign logging only responds to the DEBUG level.
application.yml
logging.level.project.user.UserClient: DEBUG
The Logger.Level object that you may configure per client, tells Feign how much to log. Choices are:
可以為每個客戶端配置日志級別(Logger.Level),選項有:
- NONE, No logging (DEFAULT).
- BASIC, Log only the request method and URL and the response status code and execution time.
- HEADERS, Log the basic information along with request and response headers.
- FULL, Log the headers, body, and metadata for both requests and responses.
For example, the following would set the Logger.Level to FULL:
下例將日志級別設為全部(FULL):
@Configuration public class FooConfiguration { @Bean Logger.Level feignLoggerLevel() { return Logger.Level.FULL; } }
dreamingodd原創文章,如轉載請注明出處。