Spring Cloud OpenFeign

Spring Cloud OpenFeign

理解OpenFeign

它声明一个REST客户端,来完成远程服务的调用,Feign会动态实现由JAX-RS或Spring MVC注解修饰的接口,主要用途是用来简化服务之间的相互调用

在SpringBoot中集成Feign

前提

已经准备好由SpringBoot构建的客户端和服务端,并且已经成功注册到Eureka注册中心。

引入相关jar

在客户端中Pom中加入

1
2
3
4
5
6
7
8
9
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>

<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-okhttp</artifactId>
</dependency>

相关配置

在客户端启动类上加上注解@EnableFeignClients

使用

声明一个接口,在接口的方法上引入SpringMvc的注解,即可完成远程服务的调用

1
2
3
4
5
6
@FeignClient(name = "clivia-service-notification-${spring.profiles.active}")
public interface NotificationClient {

@RequestMapping(method = RequestMethod.GET, value = "/")
String home();
}

使用Feign

使用OKHTTP

前面在引入jar包的时候,已经集成了okhttp相关的包

在理解这一块内容的时候,简单看了一下这一块的实现,根据官方的文档介绍

Spring Cloud Netflix提供了一些Bean,包括了Feign Client,在Ribbon开启的情况下,默认的FeignClient是LoadBalancerFeignClient

跟踪LoadBalancerFeignClient代码,它在构造器上定义了一个委派的Client,继续看这个对象。他的实现在接口内,并且最终使用的是HttpURLConnection, 也就是Java原生的远程连接对象。

回到主题,在这个包中,有一个配置类对象OkHttpFeignLoadBalancedConfiguration,开启条件是feign.okhttp.enabled=true,并且OkHttpClient存在于classpath中

继续观察当前对象

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
@Configuration
@ConditionalOnMissingBean(okhttp3.OkHttpClient.class)
protected static class OkHttpFeignConfiguration {

private okhttp3.OkHttpClient okHttpClient;

<!--定义了一个连接池-->
@Bean
@ConditionalOnMissingBean(ConnectionPool.class)
public ConnectionPool httpClientConnectionPool(
FeignHttpClientProperties httpClientProperties,
OkHttpClientConnectionPoolFactory connectionPoolFactory) {
Integer maxTotalConnections = httpClientProperties.getMaxConnections();
Long timeToLive = httpClientProperties.getTimeToLive();
TimeUnit ttlUnit = httpClientProperties.getTimeToLiveUnit();
return connectionPoolFactory.create(maxTotalConnections, timeToLive, ttlUnit);
}

<!--创建了一个OkHttpClient客户端-->
@Bean
public okhttp3.OkHttpClient client(OkHttpClientFactory httpClientFactory,
ConnectionPool connectionPool,
FeignHttpClientProperties httpClientProperties) {
Boolean followRedirects = httpClientProperties.isFollowRedirects();
Integer connectTimeout = httpClientProperties.getConnectionTimeout();
this.okHttpClient = httpClientFactory
.createBuilder(httpClientProperties.isDisableSslValidation())
.connectTimeout(connectTimeout, TimeUnit.MILLISECONDS)
.followRedirects(followRedirects).connectionPool(connectionPool)
.build();
return this.okHttpClient;
}

@PreDestroy
public void destroy() {
if (this.okHttpClient != null) {
this.okHttpClient.dispatcher().executorService().shutdown();
this.okHttpClient.connectionPool().evictAll();
}
}

}

通过对以上代码的理解,我只需要在配置中设置feign.okhttp.enabled=true,即可使用OkHttp作为服务调用的客户端工具,当然,如果在代码中自己配置了OkHttpClientBean,框架本身就不会再重复创建了,相关连接池的配置读取自配置feign.httpclient.*

最后还需要注意的就是设置Feign客户端远程调用的连接和读取的超时时间配置,这个配置需要在客户端中额外配置,默认的配置示例

1
2
3
4
5
6
7
feign:
client:
config:
default: # 客户端名称,default表示默认
connectTimeout: 6000
readTimeout: 6000 # 表示6s
loggerLevel: basic

通过修改OKHttp连接池和请求相应相关的参数来获取更好的性能

日志配置

Feign日志记录仅响应DEBUG级别日志,所以首先配置Feign Client的日志级别为DEBUG

1
2
3
logging:
level:
com.vcors.project.common.feign.NotificationClient: DEBUG

接下来配置Logger.Level,这里可以单独为每个客户端配置,也可以统一配置,下面的示例是配置到一个class中

1
2
3
4
5
6
7
8
9
@Configuration
public class FooConfiguration {
@Bean
Logger.Level feignLoggerLevel() {
return Logger.Level.FULL;
}
}

@FeignClient(name = "clivia-service-notification-${spring.profiles.active}", configuration = {DefaultFeignConfiguration.class})

日志级别

  • None 无日志,默认
  • BASIC 记录请求URL和方法及响应时间和状态
  • HEADERS 记录基本信息及请求响应头
  • FULL 记录全部的信息

数据压缩

通过GZIP压缩请求

1
2
3
4
5
6
7
feign:
compression:
request:
enabled: true
min-request-size: 2048
response:
enabled: true

HTTP BASIC认证

对服务的API增加访问保护,是非常有意义的,被请求的服务通过集成spring-boot-starter-security, 可以快速使用HTTP BASIC

这个时候Feign在调用远程服务的时候,通过加入拦截器,可以完成HTTP BASIC的验证

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
@Configuration
public class DefaultFeignConfiguration {

@Bean
Logger.Level feignLoggerLevel() {
return Logger.Level.BASIC;
}

<!--请求重试-->
@Bean
Retryer feignRetryer() {
return Retryer.NEVER_RETRY;
}

@Bean
public BasicAuthRequestInterceptor basicAuthRequestInterceptor() {
return new BasicAuthRequestInterceptor("admin", "passwd");
}
}

Comments

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×