Spring Cloud OpenFeign文档阅读
This commit is contained in:
161
spring/Spring Cloud/Spring Cloud OpenFeign.md
Normal file
161
spring/Spring Cloud/Spring Cloud OpenFeign.md
Normal file
@@ -0,0 +1,161 @@
|
|||||||
|
- [Spring Cloud OpenFeign](#spring-cloud-openfeign)
|
||||||
|
- [Feign](#feign)
|
||||||
|
- [引入Feign](#引入feign)
|
||||||
|
- [@FeignClient注解的属性解析模式](#feignclient注解的属性解析模式)
|
||||||
|
- [覆盖Feign的默认属性](#覆盖feign的默认属性)
|
||||||
|
- [重试](#重试)
|
||||||
|
- [通过Configuration类或配置文件来修改Feign Client的默认行为](#通过configuration类或配置文件来修改feign-client的默认行为)
|
||||||
|
- [超时处理](#超时处理)
|
||||||
|
- [Feign Caching](#feign-caching)
|
||||||
|
|
||||||
|
|
||||||
|
# Spring Cloud OpenFeign
|
||||||
|
## Feign
|
||||||
|
Feign是一个声明式的web service client,其能够让编写web service client的过程更加简单。在使用Feign时,只需要创建一个接口并且为其添加注解。
|
||||||
|
在使用Feign时,Spring Cloud集成了Eureka、Spring Cloud CircuitBreaker和Spring Cloud LoadBalancer来向使用者提供一个负载均衡的http client。
|
||||||
|
### 引入Feign
|
||||||
|
如果要在项目中引入Feign,可以添加如下启动器依赖:
|
||||||
|
```xml
|
||||||
|
<groupId>org.springframework.cloud</groupId>
|
||||||
|
<artifactId>spring-cloud-starter-openfeign</artifactId>
|
||||||
|
```
|
||||||
|
在使用Feign时,需要为启动类添加`@EnableFeignClients`注解,示例如下所示:
|
||||||
|
```java
|
||||||
|
@SpringBootApplication
|
||||||
|
@EnableFeignClients
|
||||||
|
public class Application {
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
SpringApplication.run(Application.class, args);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
```
|
||||||
|
使用Feign时,定义接口并添加注解的示例如下所示:
|
||||||
|
```java
|
||||||
|
@FeignClient("stores")
|
||||||
|
public interface StoreClient {
|
||||||
|
@RequestMapping(method = RequestMethod.GET, value = "/stores")
|
||||||
|
List<Store> getStores();
|
||||||
|
|
||||||
|
@RequestMapping(method = RequestMethod.GET, value = "/stores")
|
||||||
|
Page<Store> getStores(Pageable pageable);
|
||||||
|
|
||||||
|
@RequestMapping(method = RequestMethod.POST, value = "/stores/{storeId}", consumes = "application/json")
|
||||||
|
Store update(@PathVariable("storeId") Long storeId, Store store);
|
||||||
|
|
||||||
|
@RequestMapping(method = RequestMethod.DELETE, value = "/stores/{storeId:\\d+}")
|
||||||
|
void delete(@PathVariable Long storeId);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
上述示例中,@FeignClient中指定的字符串是一个任意的client name,用于创建spring cloud loadbalancer client,对于该注解还可以指定一个`url`属性。在spring context中,该bean对象的name即是接口的全类名,bean name也可以通过@FeignClient注解中的`qualifiers`属性来替换。
|
||||||
|
上述的loadbalancer client会取发现"stores" service对应的物理地址,如果你的应用是一个Eureka client,那么loadbalancer client会从Eureka注册中心中进行解析。
|
||||||
|
#### @FeignClient注解的属性解析模式
|
||||||
|
当创建Feign client bean对象时,会解析传递给@FeignClient注解的属性值。这些值默认是立即解析的。
|
||||||
|
如果如果需要延迟这些属性值的解析时机,可以配置`spring.cloud.openfeign.lazy-attributes-resolution`的值为true。
|
||||||
|
### 覆盖Feign的默认属性
|
||||||
|
Spring Cloud Feign的核心理念是命名客户端(named client)。每个Feign client都是组件集合一部分,组件集合协同工作,并且在需要时连接远程的server。该组件集合有一个名称,该值通过@FeignClient的value属性赋值。对于每个named client,Spring Cloud使用`FeignClientsConfiguration`来创建一个新的集合作为Application Client。
|
||||||
|
组件集合中包含有一个`feign.Decoder`,一个`feign.Encoder`和`feign.Contract`。可以通过@FeignClient注解中的`contextId`属性来覆盖集合name。
|
||||||
|
Spring Cloud允许通过声明额外的configuration来完全掌控feign client,示例如下:
|
||||||
|
```java
|
||||||
|
@FeignClient(name = "stores", configuration = FooConfiguration.class)
|
||||||
|
public interface StoreClient {
|
||||||
|
//..
|
||||||
|
}
|
||||||
|
```
|
||||||
|
在这种情况下,client由`FeignClientsConfiguration`中已经存在的组件和`FooConfiguration`中的组件共同组成,并且后者会覆盖前者。
|
||||||
|
> FooConfiguration类在声明时不要为其添加@Configuration注解,否则其会成为feign.Decoder, feign.Encoder, feign.Contract的默认来源。
|
||||||
|
|
||||||
|
对于`name`和`url`属性,赋值支持占位符:
|
||||||
|
```java
|
||||||
|
@FeignClient(name = "${feign.name}", url = "${feign.url}")
|
||||||
|
public interface StoreClient {
|
||||||
|
//..
|
||||||
|
}
|
||||||
|
```
|
||||||
|
#### 重试
|
||||||
|
一个`Retryer.NEVER_RETRY`的bean对象会被默认创建,其会禁止重试操作。但是,其会自动重试IOException,将IOException看作暂时性地网络异常,并且在ErrorDecoder中抛出RetryableException。
|
||||||
|
在@FeignClient注解`configuration`属性指定的配置类中创建Bean对象可以允许覆盖默认的bean对象,示例如下:
|
||||||
|
```java
|
||||||
|
@Configuration
|
||||||
|
public class FooConfiguration {
|
||||||
|
@Bean
|
||||||
|
public Contract feignContract() {
|
||||||
|
return new feign.Contract.Default();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public BasicAuthRequestInterceptor basicAuthRequestInterceptor() {
|
||||||
|
return new BasicAuthRequestInterceptor("user", "password");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
#### 通过Configuration类或配置文件来修改Feign Client的默认行为
|
||||||
|
@FeignClient也可以通过配置文件来进行配置:
|
||||||
|
```yml
|
||||||
|
spring:
|
||||||
|
cloud:
|
||||||
|
openfeign:
|
||||||
|
client:
|
||||||
|
config:
|
||||||
|
{feignName}:
|
||||||
|
url: http://remote-service.com
|
||||||
|
connectTimeout: 5000
|
||||||
|
readTimeout: 5000
|
||||||
|
loggerLevel: full
|
||||||
|
errorDecoder: com.example.SimpleErrorDecoder
|
||||||
|
retryer: com.example.SimpleRetryer
|
||||||
|
defaultQueryParameters:
|
||||||
|
query: queryValue
|
||||||
|
defaultRequestHeaders:
|
||||||
|
header: headerValue
|
||||||
|
requestInterceptors:
|
||||||
|
- com.example.FooRequestInterceptor
|
||||||
|
- com.example.BarRequestInterceptor
|
||||||
|
responseInterceptor: com.example.BazResponseInterceptor
|
||||||
|
dismiss404: false
|
||||||
|
encoder: com.example.SimpleEncoder
|
||||||
|
decoder: com.example.SimpleDecoder
|
||||||
|
contract: com.example.SimpleContract
|
||||||
|
capabilities:
|
||||||
|
- com.example.FooCapability
|
||||||
|
- com.example.BarCapability
|
||||||
|
queryMapEncoder: com.example.SimpleQueryMapEncoder
|
||||||
|
micrometer.enabled: false
|
||||||
|
```
|
||||||
|
feignName在上述配置文件中代表@FeignClient注解中的value值。
|
||||||
|
> 若feignName的值为default,可以将配置应用于所有的feign client。
|
||||||
|
|
||||||
|
可以在`@EnableFeignClients`注解中指定defaultConfiguration属性,其可以指定一个自定义的默认配置类,覆盖的行为会作用于所有的Feign Client。
|
||||||
|
可以使用`spring.cloud.openfeign.client.config.feignName.defaultQueryParameters`和`spring.cloud.openfeign.client.config.feignName.defaultRequestHeaders`来指定client每次请求都会发送的请求参数和请求header。
|
||||||
|
|
||||||
|
如果在创建Configuration类的同时也指定了配置文件,那么配置文件的优先级更高,配置文件的值会覆盖Configuration类中的值。
|
||||||
|
如果想要多个feign client拥有相同的name和url,以使它们指向同一个server,但不同feign client拥有不同的配置。可以为它们指定不同的`contextId`。
|
||||||
|
```java
|
||||||
|
@FeignClient(contextId = "fooClient", name = "stores", configuration = FooConfiguration.class)
|
||||||
|
public interface FooClient {
|
||||||
|
//..
|
||||||
|
}
|
||||||
|
@FeignClient(contextId = "barClient", name = "stores", configuration = BarConfiguration.class)
|
||||||
|
public interface BarClient {
|
||||||
|
//..
|
||||||
|
}
|
||||||
|
```
|
||||||
|
### 超时处理
|
||||||
|
可以为named client或所有client指定超时处理。OpenFeign使用两个timeout参数:
|
||||||
|
- connectTimeout:该属性避免server长时间处理造成的调用方阻塞
|
||||||
|
- readTimeout:该属性从连接建立时开始应用,并且当返回响应过慢时被触发(该参数衡量的是从建立连接到返回响应的过程)
|
||||||
|
|
||||||
|
### Feign Caching
|
||||||
|
当使用@EnableCaching之后,一个`CachingCapability`的bean对象将会被配置,Feign client将会识别接口上的`@Cache*`注解。
|
||||||
|
```java
|
||||||
|
public interface DemoClient {
|
||||||
|
|
||||||
|
@GetMapping("/demo/{filterParam}")
|
||||||
|
@Cacheable(cacheNames = "demo-cache", key = "#keyParam")
|
||||||
|
String demoEndpoint(String keyParam, @PathVariable String filterParam);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Reference in New Issue
Block a user