繁体   English   中英

如何将自定义 Http 客户端注入 Spring Cloud openfeign?

[英]How to inject custom Http client to Spring Cloud openfeign?

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

基本上,我将 SSLContext 提供给 HTTP 客户端,并且我希望 Feign 使用这个加载了 SSLContext 的客户端。 如何将此 CloseableHttpClient 注入 Feign?

以下是我的相关配置:

  1. 我正在使用 SpringBootApp
@SpringBootApplication
@EnableFeignClients
public class Application extends SpringBootServletInitializer {

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
  1. Feign客户端界面如下:
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. 在 application.properties 中将 feign.httpclient.enabled 设置为 true
  2. Springboot 版本为 2.4.4。 Feign 版本是 feign-core-10.10.1

我不明白的其他部分,Spring 将如何将这个自定义的 CloseableHttpClient 挂钩到 Feign,因为它声称。 Because when I debug, at runtime I see the Feign annotated interface is implemented by feign.SynchronousMethodHandler class and the 'client' field in this class is of type feign.Client and at runtime it gets com.sun.security.ntlm.Client (可能是默认实现)。 CloseableHttpClient 应该如何注入到 feign.Client 中? web 上很少有这样的例子,他们没有解释。

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

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

您需要将@Configuration放在FeignConfig ,我相信它应该可以正常工作。

在我们注入的 bean 中,我们必须提供feign.Client的实现。 最简单的是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());
        }
}

经验教训:

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

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

最重要的是,OpenFeign 的 Github 文档谈到了使用 ApacheHttpClient。

这可能会使人感到困惑。 我的问题的第二部分“我不明白的其他部分,Spring 如何将这个自定义 CloseableHttpClient 挂钩到 Feign,因为它声称......这个 class 中的 'client' 字段是 feign.Client 类型"

回答:

没有什么魔法,ApacheHttpClient OpenFeign Github 文档谈到的是 OpenFeign 对 Apache 的 HttpClient 库ApacheHttpClient的包装,它实现了 feign.Client接口。

并且此 ApacheHttpClient 实现在 Spring Openfeign 的引导启动器附带的 feign core 10.1.1 依赖项中不可用。

我曾遇到过同样的问题(尽管使用 OkHttpClient 而不是 ApacheHttpClient)。 你的问题和回答帮助了我。 谢谢!

对我而言,关键是在自动配置 class ( 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)

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

有趣的是, OkHttpFeignConfiguration本身负责将 http 客户端包装在它自己的包装器 class 中(就像您在自己的答案中的 state 一样):

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

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

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

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

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

ApacheHttpClient 案例中的逻辑完全相同。

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

据我所知,文档没有说明我们必须自己配置这个“包装器 bean”。 我可能在某个地方遗漏了一些重要的东西,或者在最新版本的库中这种行为可能发生了变化。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM