在默認狀況下 spring cloud feign在進行各個子服務之間的調用時,http組件使用的是jdk的HttpURLConnection,沒有使用線程池。本文先從源碼分析feign的http組件對象生成的過程,而後經過爲feign配置http線程池優化調用效率。java
咱們分析源碼spring cloud feign。在spring-cloud-netflix-core/META-INF/spring.factories中能夠看到,在spring boot自動配置會初始化FeignRibbonClientAutoConfiguration,這個類會生成Ribbon的使用http組件。git
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.cloud.netflix.feign.ribbon.FeignRibbonClientAutoConfiguration,\
複製代碼
分析配置類是FeignRibbonClientAutoConfiguration 下面分析此類import的3個類:HttpClientFeignLoadBalancedConfiguration,OkHttpFeignLoadBalancedConfiguration,DefaultFeignLoadBalancedConfigurationgithub
@Import({ HttpClientFeignLoadBalancedConfiguration.class,
OkHttpFeignLoadBalancedConfiguration.class,
DefaultFeignLoadBalancedConfiguration.class })
public class FeignRibbonClientAutoConfiguration {
…
}
複製代碼
HttpClientFeignLoadBalancedConfiguration 爲feigin配置appache client的線程池 當引入ApacheHttpClient.class類時,會初始化這個配置類 方法feignClient()中:根據@ConditionalOnMissingBean(Client.class)知道若是有HttpClient 對象,則建立的ApacheHttpClient使用本身定義的HttpClient 。若是沒有,則使用默認值。最後生成LoadBalancerFeignClient對象spring
@Configuration
@ConditionalOnClass(ApacheHttpClient.class)
@ConditionalOnProperty(value = "feign.httpclient.enabled", matchIfMissing = true)
class HttpClientFeignLoadBalancedConfiguration {
@Autowired(required = false)
private HttpClient httpClient;
@Bean
@ConditionalOnMissingBean(Client.class)
public Client feignClient(CachingSpringLoadBalancerFactory cachingFactory,
SpringClientFactory clientFactory) {
ApacheHttpClient delegate;
if (this.httpClient != null) {
delegate = new ApacheHttpClient(this.httpClient);
} else {
delegate = new ApacheHttpClient();
}
return new LoadBalancerFeignClient(delegate, cachingFactory, clientFactory);
}
}
複製代碼
OkHttpFeignLoadBalancedConfiguration 爲feigin配置OkHttp,相似apache httpclient, 這裏略。 DefaultFeignLoadBalancedConfiguration 爲feigin配置HttpURLConnection, 方法feignClient():只有以上兩個Client沒有生產對象時,纔在這個方法中使用Client.Default生成LoadBalancerFeignClientapache
@Configuration
class DefaultFeignLoadBalancedConfiguration {
@Bean
@ConditionalOnMissingBean
public Client feignClient(CachingSpringLoadBalancerFactory cachingFactory,
SpringClientFactory clientFactory) {
return new LoadBalancerFeignClient(new Client.Default(null, null),
cachingFactory, clientFactory);
}
}
複製代碼
查看Client.Default的源碼,Default 使用HttpURLConnection 創建鏈接且每次請求都創建一個新的鏈接bash
public static class Default implements Client {
@Override
public Response execute(Request request, Options options) throws IOException {
HttpURLConnection connection = convertAndSend(request, options);
return convertResponse(connection).toBuilder().request(request).build();
}
….
}
複製代碼
綜上所述,在默認狀況下,spring cloud 沒有引入httpclient和okhttp的jar包,全部默認使用HttpURLConnection併發
默認狀況下,服務之間調用使用的HttpURLConnection,效率很是低。爲了提升效率,能夠經過鏈接池提升效率,本節咱們使用appache httpclient作爲鏈接池。配置OkHttpClient鏈接池,也是相似的方法,這裏略。 通過上節的分析,配置線程池方法:引入appache httpclient並啓動對應配置,最後還須要生成HttpClient對象。app
<!-- 增長feign-httpclient -->
<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-httpclient</artifactId>
</dependency>
複製代碼
# feign配置
feign:
hystrix:
# 在feign中開啓hystrix功能,默認狀況下feign不開啓hystrix功能
enabled: true
## 配置httpclient線程池
httpclient:
enabled: true
okhttp:
enabled: false
複製代碼
使用配置類,生成HttpClient 對象。由於使用PoolingHttpClientConnectionManager鏈接池,咱們須要啓動定時器,定時回收過時的鏈接。配置定時回收鏈接池的緣由,見問題備忘: httpclient鏈接池異常引起的慘案ide
@Configuration
public class HttpPool {
@Bean
public HttpClient httpClient(){
System.out.println("init feign httpclient configuration " );
// 生成默認請求配置
RequestConfig.Builder requestConfigBuilder = RequestConfig.custom();
// 超時時間
requestConfigBuilder.setSocketTimeout(5 * 1000);
// 鏈接時間
requestConfigBuilder.setConnectTimeout(5 * 1000);
RequestConfig defaultRequestConfig = requestConfigBuilder.build();
// 鏈接池配置
// 長鏈接保持30秒
final PoolingHttpClientConnectionManager pollingConnectionManager = new PoolingHttpClientConnectionManager(30, TimeUnit.MILLISECONDS);
// 總鏈接數
pollingConnectionManager.setMaxTotal(5000);
// 同路由的併發數
pollingConnectionManager.setDefaultMaxPerRoute(100);
// httpclient 配置
HttpClientBuilder httpClientBuilder = HttpClientBuilder.create();
// 保持長鏈接配置,須要在頭添加Keep-Alive
httpClientBuilder.setKeepAliveStrategy(new DefaultConnectionKeepAliveStrategy());
httpClientBuilder.setConnectionManager(pollingConnectionManager);
httpClientBuilder.setDefaultRequestConfig(defaultRequestConfig);
HttpClient client = httpClientBuilder.build();
// 啓動定時器,定時回收過時的鏈接
Timer timer = new Timer();
timer.schedule(new TimerTask() {
@Override
public void run() {
// System.out.println("=====closeIdleConnections===");
pollingConnectionManager.closeExpiredConnections();
pollingConnectionManager.closeIdleConnections(5, TimeUnit.SECONDS);
}
}, 10 * 1000, 5 * 1000);
System.out.println("===== Apache httpclient 初始化鏈接池===");
return client;
}
}
複製代碼
啓動工程:cloud-registration-center、cloud-service-hystrix 啓動服務:HystrixFeignCloudConsumerApplication 執行請求:http://127.0.0.1:12082/hystrix-feign/simple源碼分析
配置日誌爲debug輸出(設置logback-spring.xml爲 level爲DEBUG),若是日誌有相似一下的輸出(包含PoolingHttpClientConnectionManager ),則表示鏈接池配置成功
2018-04-09 23:11:49.017 [hystrix-cloud-hystrix-service-1] DEBUG o.a.h.i.c.PoolingHttpClientConnectionManager - Connection request: [route: {}->http://192.168.0.113:12081][total kept alive: 0; route allocated: 0 of 100; total allocated: 0 of 5000]
2018-04-09 23:11:49.020 [hystrix-cloud-hystrix-service-1] DEBUG o.a.h.i.c.PoolingHttpClientConnectionManager - Connection leased: [id: 0][route: {}->http://192.168.0.113:12081][total kept alive: 0; route allocated: 1 of 100; total allocated: 1 of 5000]
複製代碼
以上的詳細的代碼見下面 github代碼,請儘可能使用tag v0.12,不要使用master,由於我不能保證master代碼一直不變