文章摘要(AI生成)
声明性REST客户端:feignFeign是一个声明性的Web服务客户端,它使编写Web服务客户端变得更容易。要使用Feign,需要创建接口并对其进行注释。它具有可插入的注释支持,包括Feign注释和JAX-RS注释。Feign还支持可插拔编码器和解码器。Spring Cloud增加了对Spring
声明性REST客户端:feign
Feign是一个声明性的Web服务客户端,它使编写Web服务客户端变得更容易。要使用Feign,需要创建接口并对其进行注释。它具有可插入的注释支持,包括Feign注释和JAX-RS注释。Feign还支持可插拔编码器和解码器。Spring Cloud增加了对Spring MVC注释的支持,并使用了Spring Web中默认使用HttpMessageConverters
的注释。Spring Cloud集成了Ribbon和Eureka,在使用Feign时提供负载均衡的http客户端。
23.1如何使用feign
要在项目中使用Feign,请使用引用group为org.springframework.cloud
artifact id 为spring-cloud-starter-openfeign
启动器。有关使用当前Spring Cloud Release Train设置构建项目的详细信息,请参阅Spring Cloud Project页面。
Spring boot启动应用示例
@SpringBootApplication
@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
注释中,字符串值(例如上面的“stores”)是一个任意客户端名称,用于创建Ribbon负载均衡器(有关功能区支持的详细信息,请参见下文)。您还可以使用url
属性(绝对值或主机名)指定URL 。应用程序上下文中bean的名称是接口的完全限定名称。要指定自己的别名值,可以使用注释的qualifier
值@FeignClient
。
上面的Ribbon客户端将要发现“stores”服务的物理地址。如果您的应用程序是Eureka客户端,那么它将解析Eureka服务注册表中的服务。如果您不想使用Eureka,只需在外部配置中配置服务器列表(例如,参见 上文)。
23.2重写feign默认值
Spring Cloud的Feign支持的核心概念是指定客户端的概念。每个feign客户端都是一组组件接口的集合,这些组件一起工作并按需联系远程服务器,并且该集合具有使用@FeignClient
注释提供的服务名称。Spring Cloud根据ApplicationContext
需要为每个命名客户端创建一个新的集合FeignClientsConfiguration
。这包含(除其他外)feign.Decoder
, feign.Encoder
和 feign.Contract
。可以使用注释的contextId
属性覆盖该集合的名称@FeignClient
。
Spring Cloud允许通过声明其他配置(在其之上为feign默认配置FeignClientsConfiguration
)使用来完全控制feign客户端@FeignClient
。例:
@FeignClient(name =“stores”,configuration = FooConfiguration.class)
public interface StoreClient {
// ..
}
在这种情况下,客户端由已经FeignClientsConfiguration
与在FooConfiguration
中的其他组件一并控制(后者将覆盖前者)。
FooConfiguration 不需要使用注释@Configuration 。但是,如果使用的话,它将不包括任何由@ComponentScan 组件扫描器扫描到的其他配置,并且会包含此配置,它将成为feign.Decoder ,feign.Encoder ,feign.Contract 等的默认来源。这把它当作一个单独的,非重叠的包从而避免@ComponentScan 或@SpringBootApplication ,或者它可以被明确地排除在@ComponentScan 之外。 |
serviceId 现在不推荐使用该属性,而是使用该name 属性。 |
除了更改ApplicationContext 的名称之外,还使用@FeignClient 中contextId 属性的注释,它将覆盖客户端名称的别名,并将其用作为该客户端创建的配置Bean的名称部分。 |
以前,使用该url 属性不需要name 属性。name 现在需要使用。 |
在name
和url
属性中支持占位符。
@FeignClient(name = "${feign.name}", url = "${feign.url}")
public interface StoreClient {
//..
}
Spring Cloud Netflix为feign提供了以下bean配置feign的属性(BeanType
bean名称 : ClassName
):
Decoder
feign解码器 😦ResponseEntityDecoder
包装一个SpringDecoder
)Encoder
feign编码器:SpringEncoder
Logger
feign日志:Slf4jLogger
Contract
feignContract:SpringMvcContract
Feign.Builder
feignBuilder:HystrixFeign.Builder
Client
feignClient:如果启用了ribbon,则为一个LoadBalancerFeignClient
,否则使用默认的假设客户端。
OkHttpClient和ApacheHttpClient feign客户端可以分别通过设置使用feign.okhttp.enabled
或feign.httpclient.enabled
为true
到具有它们的类路径上。当通过Apache或OkHttpClient
使用OK HTTP 的时候,您可以通过使用ClosableHttpClient
定制HTTP客户端。
对于默认的feign,Spring Cloud Netflix 不提供以下bean,但仍然可以从application context 中查找这些类型的bean以创建feign客户端:
Logger.Level
Retryer
ErrorDecoder
Request.Options
Collection<RequestInterceptor>
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
集合中。
@FeignClient
也可以使用配置属性进行配置。
application.yml
feign:
client:
config:
feignName:
connectTimeout: 5000
readTimeout: 5000
loggerLevel: full
errorDecoder: com.example.SimpleErrorDecoder
retryer: com.example.SimpleRetryer
requestInterceptors:
- com.example.FooRequestInterceptor
- com.example.BarRequestInterceptor
decode404: false
encoder: com.example.SimpleEncoder
decoder: com.example.SimpleDecoder
contract: com.example.SimpleContract
与上述配置方式相似,可以使用@EnableFeignClients
的属性defaultConfiguration
中指定默认配置。不同之处在于此配置将适用于所有的feign客户端。
如果您更喜欢使用配置属性来配置所有的 @FeignClient
,则可以使用default
创建feign的配置属性。
application.yml
feign:
client:
config:
default:
connectTimeout:5000
readTimeout:5000
loggerLevel:basic
如果我们既创建@Configuration
bean又配置了属性文件,配置属性将会生效。它将覆盖@Configuration
值。但是如果要将优先级更改为@Configuration
,则可以更改feign.client.default-to-properties
为false
。
如果在RequestInterceptor 中使用了ThreadLocal 绑定变量,您需要将Hystrix的线程隔离策略设置为SEMAPHORE 或在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
如果我们想要创建具有相同名称或URL的多个feign客户端,以便它们指向同一服务器但每个都具有不同的自定义配置,那么我们必须使用该contextId
属性@FeignClient
以避免这些配置bean的名称冲突。
@FeignClient(contextId =“fooClient”,name =“stores”,configuration = FooConfiguration.class)
public interface FooClient {
// ..
}
@FeignClient(contextId =“barClient”,name =“stores”,configuration = BarConfiguration.class)
public interface BarClient {
// ..
}
23.3手动创建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, Contract contract) {
this.fooClient = Feign.builder().client(client)
.encoder(encoder)
.decoder(decoder)
.contract(contract)
.requestInterceptor(new BasicAuthRequestInterceptor("user", "user"))
.target(FooClient.class, "http://PROD-SVC");
this.adminClient = Feign.builder().client(client)
.encoder(encoder)
.decoder(decoder)
.contract(contract)
.requestInterceptor(new BasicAuthRequestInterceptor("admin", "admin"))
.target(FooClient.class, "http://PROD-SVC");
}
}
在上面的示例中FeignClientsConfiguration.class 是Spring Cloud Netflix提供的默认配置。 |
PROD-SVC 是客户端将要求的服务的名称。 |
Feign Contract 对象定义注释和值在接口上有效。autowired Contract bean提供对SpringMVC注释的支持,而不是默认的Feign本地注释。 |
23.4 Feign Hystrix支持
如果引用了Hystrix,并且定义feign.hystrix.enabled=true
,Feign将使用断路器中的所有方法。返回一个 可用的com.netflix.hystrix.HystrixCommand
。这允许您使用反应模式(调用.toObservable()
或.observe()
或异步使用(调用.queue()
)。
要在每个客户端的基础上禁用Hystrix支持,请创建Feign.Builder
具有“原型”范围的vanilla ,例如:
@Configuration
public class FooConfiguration {
@Bean
@Scope("prototype")
public Feign.Builder feignBuilder() {
return Feign.builder();
}
}
在Spring Cloud Dalston发布之前,如果Hystrix在类路径上,Feign会默认将所有方法包装在断路器中。Spring Cloud Dalston中更改了此默认行为,转而采用了选择加入方法。 |
23.5 Feign Hystrix回退
Hystrix支持回退的概念:当电路打开或出现错误时执行的默认代码路径。要为给定@FeignClient
集启用回退,请将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");
}
}
如果需要访问导致回退触发器的原因,可以使用fallbackFactory
内部属性@FeignClient
。
@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 HystrixClient() {
@Override
public Hello iFailSometimes() {
return new Hello("fallback; reason was: " + cause.getMessage());
}
};
}
}
在Feign中实现回退以及Hystrix回退如何工作存在限制。返回com.netflix.hystrix.HystrixCommand 和返回的方法目前不支持回退rx.Observable 。 |
23.6feign和 @Primary
当使用Feign with Hystrix后备时,ApplicationContext
同一类型中有多个bean 。这将导致@Autowired
无法正常工作,因为没有一个bean或一个标记为primary的bean。为了解决这个问题,Spring Cloud Netflix将所有Feign实例标记为@Primary
,因此Spring Framework将知道要注入哪个bean。在某些情况下,这可能并不理想。要关闭此行为,请将primary
属性设置@FeignClient
为false。
@FeignClient(name = "hello", primary = false)
public interface HelloClient {
// methods here
}
23.7 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(方法参数映射不会被继承)。 |
23.8 Feign请求/响应压缩
您可以考虑为您的Feign请求启用请求或响应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
通过这些属性,您可以选择压缩介质类型和最小请求阈值长度。
23.9记录日志
为每个创建的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;
}
}
23.10 Feign @QueryMap支持
OpenFeign @QueryMap
注释为POJO提供了对用作GET参数映射的支持。不幸的是,默认的OpenFeign QueryMap注释与Spring不兼容,因为它缺少value
属性。
Spring Cloud OpenFeign提供等效@SpringQueryMap
注释,用于将POJO或Map参数注释为查询参数映射。
例如,Params
该类定义参数param1
和param2
:
// Params.java
public class Params {
private String param1;
private String param2;
// [Getters and setters omitted for brevity]
}
以下feign客户端使用注释使用Params
该类@SpringQueryMap
:
@FeignClient("demo")
public class DemoTemplate {
@GetMapping(path = "/demo")
String demoEndpoint(@SpringQueryMap Params params);
}
评论区