如何将自定义 Http 客户端注入到春云开假?



我正在尝试为Spring Cloud OpenFeign提供CloseableHttpClient。 Spring Cloud Open Feign Documentation表示它支持CloeableHttpClient。 Spring 文档没有给出任何实际替换 HTTP 客户端的示例。

基本上,我向HTTP客户端提供SSLContext,我希望Feign使用这个SSLContext加载的客户端。 如何将这个 CloseableHttpClient 注入到假装中?

以下是我的相关配置:

  1. 我正在使用 SpringBootApp
@SpringBootApplication
@EnableFeignClients
public class Application extends SpringBootServletInitializer {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
  1. 假客户端接口如下:
import org.springframework.cloud.openfeign.FeignClient;
//skipping rest of the imports for brevity
@FeignClient(name ="remote-service", url = "${remote.service-url}", configuration = FeignConfig.class)
public interface RemoteServiceApi {
@GetMapping(value = "/api/v1/resources/{Id}")
public String getResource(@PathVariable("Id") String Id);
}
  1. FeignConfig class
import org.apache.http.impl.client.CloseableHttpClient;
//skipping rest of the imports for brevity
public class FeignConfig {
@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;
}
}
  1. 在应用程序中,属性 feign.httpclient.enabled 设置为 true
  2. Springboot 版本是 2.4.4。假装版本是假核-10.10.1

我不明白的另一部分,Spring将如何像它声称的那样将这个自定义的CloseableHttpClient挂在假装上。因为当我调试时,在运行时我看到 Feign 注释接口是通过 fake 实现的。SyncMethodHandler 类和此类中的"client"字段的类型为 feign。客户端,在运行时它获得com.sun.security.ntlm.Client(可能是默认实现)。 CloseableHttpClient应该如何被注入假装。客户? 网络上很少有这样的事情的例子,他们没有解释它。

我在 SOF 上找到了这篇文章,但是

  1. 这里也注入了 CloseableHttpClient 类型的@Bean
  2. 对此没有有用的答案。

在我们注入的豆子中,我们必须提供假装。客户的实施。最简单的是new Client.Default(SSLSocketFactory, HostnameVerifier).我在问题中更改了代码中的 httpClient @Bean注入:

@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;
}

自:

@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());
}
}

从经验中学到:

当文档说,"您可以通过在使用 Apache 时提供 ClosableHttpClient 的 bean 来自定义使用的 HTTP 客户端,或者在使用 OK HTTP 时提供 OkHttpClient。

然后人们说他们提供了CloseableHttpClient,因为它在这个没有得到正确回答的问题中。其中的豆子注入永远不会起作用。

最重要的是,OpenFeign的Github文档讨论了使用ApacheHttpClient。

这可能会让一个人感到困惑。我问题的第二部分 "我不明白的另一部分,春天将如何钩住这个自定义的CloseableHttpClient来假装,因为它声称..... 此类中的"客户端"字段的类型为 feign。客户">

回答:

没有魔法,ApacheHttpClient OpenFeign Github文档谈论的是OpenFeign在Apache的HttpClient库ApacheHttpClient上的包装器,它实现了假装。客户端界面。

而且这个 ApacheHttpClient 实现在 Spring Boot 启动器附带的 openfeign 核心 10.1.1 依赖项中不可用。

我一直在与同样的问题作斗争(尽管使用OkHttpClient而不是ApacheHttpClient)。你的问题和答案帮助了我。谢谢!

对我来说,关键是在自动配置类(FeignAutoConfiguration)中,我们发现以下内容:

@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(OkHttpClient.class)
@ConditionalOnMissingClass("com.netflix.loadbalancer.ILoadBalancer")
@ConditionalOnMissingBean(okhttp3.OkHttpClient.class)
@ConditionalOnProperty("feign.okhttp.enabled")
protected static class OkHttpFeignConfiguration {

。最感兴趣的是:

@ConditionalOnMissingBean(okhttp3.OkHttpClient.class)

。这有效地使 Spring 在提供自己的 http 客户端 bean 时忽略了该配置(如文档中所述)。

有趣的是,OkHttpFeignConfiguration本身负责将 http 客户端包装在它自己的包装类中(正如你在自己的答案中所说的):

@Bean
@ConditionalOnMissingBean(Client.class)
public Client feignClient(okhttp3.OkHttpClient client) {
return new OkHttpClient(client);
}

因此,当我们提供自己的 http 客户端 bean 时,我们有效地禁用了包装器的自动实例化。由于 Feign 在应用程序上下文中找不到其客户端类型的 bean,因此它会自行创建一个;默认客户端。因此,我们的 http 客户端 bean 被有效地忽略了......

我的解决方案是在配置中自己进行"包装":

@Bean
fun feignClient(client: OkHttpClient) = feign.okhttp.OkHttpClient(client)

当这个 bean 存在于应用程序上下文中时,Feign 将使用它,而不是创建其默认客户端。

在ApacheHttpClient案例中,逻辑完全相同。

上述解决方案经过测试,适用于 Feign 全局配置和特定于客户端的配置。

据我所知,文档没有说我们必须自己配置这个"包装豆"。我可能在某个地方错过了一些重要的东西,或者最新版本的图书馆中可能对这个beahviour进行了更改。

你需要把@Configuration放在FeignConfig上面,我相信这应该让它工作。

最新更新