我正在尝试为Spring Cloud OpenFeign提供CloseableHttpClient。 Spring Cloud Open Feign Documentation表示它支持CloeableHttpClient。 Spring 文档没有给出任何实际替换 HTTP 客户端的示例。
基本上,我向HTTP客户端提供SSLContext,我希望Feign使用这个SSLContext加载的客户端。 如何将这个 CloseableHttpClient 注入到假装中?
以下是我的相关配置:
- 我正在使用 SpringBootApp
@SpringBootApplication
@EnableFeignClients
public class Application extends SpringBootServletInitializer {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
- 假客户端接口如下:
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);
}
- 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;
}
}
- 在应用程序中,属性 feign.httpclient.enabled 设置为 true
- Springboot 版本是 2.4.4。假装版本是假核-10.10.1
我不明白的另一部分,Spring将如何像它声称的那样将这个自定义的CloseableHttpClient挂在假装上。因为当我调试时,在运行时我看到 Feign 注释接口是通过 fake 实现的。SyncMethodHandler 类和此类中的"client"字段的类型为 feign。客户端,在运行时它获得com.sun.security.ntlm.Client(可能是默认实现)。 CloseableHttpClient应该如何被注入假装。客户? 网络上很少有这样的事情的例子,他们没有解释它。
我在 SOF 上找到了这篇文章,但是
- 这里也注入了 CloseableHttpClient 类型的@Bean
- 对此没有有用的答案。
在我们注入的豆子中,我们必须提供假装。客户的实施。最简单的是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
上面,我相信这应该让它工作。