理解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作为服务调用的客户端工具,当然,如果在代码中自己配置了OkHttpClient
Bean,框架本身就不会再重复创建了,相关连接池的配置读取自配置feign.httpclient.*
最后还需要注意的就是设置Feign客户端远程调用的连接和读取的超时时间配置,这个配置需要在客户端中额外配置,默认的配置示例
1 2 3 4 5 6 7
| feign: client: config: default: connectTimeout: 6000 readTimeout: 6000 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"); } }
|