Please refer to the following link on how to customize it. https://codingnconcepts.com/spring-boot/change-default-feign-client-implementation/
<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-httpclient</artifactId>
</dependency>
IN application.properties or yaml file
feign.httpclient.enabled: true
@Configuration
public class FeignClientConfig {
@Bean
public CloseableHttpClient feignClient() {
PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager(10, TimeUnit.MINUTES);
connectionManager.setMaxTotal(1000);
connectionManager.setDefaultMaxPerRoute(20);
CloseableHttpClient httpClient = HttpClients.custom()
.setConnectionManager(connectionManager)
.build())
Thread th = new IdleConnectionMonitorThread(connectionManager);
th.start();
return httpClient;
}
}
static class IdleConnectionMonitorThread extends Thread {
private volatile boolean shutdown;
private PoolingHttpClientConnectionManager connMgr;
public IdleConnectionMonitorThread(PoolingHttpClientConnectionManager connMgr) {
super();
this.setName("TCP-Ideal-Monitroing-Thread");
this.connMgr = connMgr;
}
@Override
public void run() {
try {
while (!shutdown) {
sleep(TimeUnit.MINUTES.toMillis(1));
// Close expired connections
connMgr.closeExpiredConnections();
// Optionally, close connections
// that have been idle longer than 60 sec
connMgr.closeIdleConnections(10, TimeUnit.MINUTES);
}
} catch (InterruptedException ex) {
// terminate
}
}
public void shutdown() {
shutdown = true;
}
}
Answer from Bmis13 on Stack OverflowIt's impossible to tell without seeing your Spring setup, especially if your application is complex like you said.
Since you are using Spring annotations to declare your @FeignClient you most likely are depending on spring-cloud-netflix-core. If you are enabling defaults with @EnableFeignClients take a look at FeignAutoConfiguration class. This class registers the actual HTTP client bean. If you add both feign.httpclient.enabled and feign.okhttp.enabled properties (which IMO is a weird setup) try debugging FeignAutoConfiguration to see which Client feignClient() bean will be registered in the Spring context.
Alternatively enable wire logging in all HTTP client libraries and see which one actually executes the request based on logs.
you can add breakpoint in feign.Client#execute and debug your program
In the bean that we are injecting we have to provide feign.Client's implementation. Simplest is new Client.Default(SSLSocketFactory, HostnameVerifier). I changed the httpClient @Bean injection in code in my question from:
@Bean
public CloseableHttpClient client() {
CloseableHttpClient httpClient=null;
try {
//... Skipping code for brevity.
//here creating "sslSocketFactory" used in the HttpClient builder below
httpClient = HttpClients.custom().setSSLSocketFactory(sslSocketFactory)
.setMaxConnTotal(10)
.setMaxConnPerRoute(10)
.build();
}catch(IOException | KeyManagementException | UnrecoverableKeyException | NoSuchAlgorithmException | KeyStoreException | CertificateException e) {
System.err.println("Exception during creation of HttpClient. : "+e.getMessage());
}
return httpClient;
}
to :
@Bean
public feign.Client client() {
feign.Client client=null;
try {
//... Skipping code for brevity.
//here creating "sslSocketFactory" used in the HttpClient builder below
client = new Client.Default(sslSocketFactory, new DefaultHostnameVerifier());
}catch(IOException | KeyManagementException | UnrecoverableKeyException | NoSuchAlgorithmException | KeyStoreException | CertificateException e) {
System.err.println("Exception during creation of HttpClient. : "+e.getMessage());
}
}
Learnings from the experience:
When the documentation says, "You can customize the HTTP client used by providing a bean of either ClosableHttpClient when using Apache or OkHttpClient when using OK HTTP."
And then people say they provided CloseableHttpClient as it is in this question which is not answered properly. The bean injection in this will never work.
On the top of that, the OpenFeign's Github documentation talks about using ApacheHttpClient.
This may leave a person confused. The second part in my question
"Other part which I didn't understand, how the Spring was going to hook this custom CloseableHttpClient to Feign as it claims.....
the 'client' field in this class is of type feign.Client "
Answer:
There is no magic, what the ApacheHttpClient OpenFeign Github documentation talks about is OpenFeign's wrapper on the Apache's HttpClient library ApacheHttpClient it implements feign.Client interface.
And this ApacheHttpClient implementation is not available in feign core 10.1.1 dependency that comes with Spring Boot starter for openfeign.
I've had a struggle with this same problem (although using OkHttpClient instead of ApacheHttpClient). Your question and answer helped me out. Thanks!
The key for me was that in the auto-configuration class (FeignAutoConfiguration) we find the following:
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(OkHttpClient.class)
@ConditionalOnMissingClass("com.netflix.loadbalancer.ILoadBalancer")
@ConditionalOnMissingBean(okhttp3.OkHttpClient.class)
@ConditionalOnProperty("feign.okhttp.enabled")
protected static class OkHttpFeignConfiguration {
...where this line is of most interest:
@ConditionalOnMissingBean(okhttp3.OkHttpClient.class)
...which effectively makes Spring ignore that configuration when we provide our own http client bean (as stated in the documentation).
What makes this interesting is that the OkHttpFeignConfiguration is itself responsible for the wrapping of the http client in it's own wrapper class (as you state in your own answer):
@Bean
@ConditionalOnMissingBean(Client.class)
public Client feignClient(okhttp3.OkHttpClient client) {
return new OkHttpClient(client);
}
So, when we do provide our own http client bean, we effectively disable the automatic instantiation of the wrapper. Since Feign does not find a bean of its Client type in the application context it creates one on its own; the Default.Client. Hence, our http client bean is effectively ignored...
The solution for me was to do "the wrapping" myself in the configuration:
@Bean
fun feignClient(client: OkHttpClient) = feign.okhttp.OkHttpClient(client)
When this bean is present in the application context Feign will make use of it rather than creating its default client.
The logic is exactly the same in the ApacheHttpClient case.
The above solution is tested to work for both Feign global configuration and client-specific configuration.
As far as I can tell the documentation says nothing about us having to configure this "wrapper bean" ourself. I might have missed something important, somewhere, or there might have been changes to this beahviour in the latest versions of the library.