欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

Feign 使用HttpClient和OkHttp方式

程序员文章站 2024-01-13 10:33:52
目录使用httpclient和okhttp使用httpclient使用okhttpopenfeign替换为okhttp使用httpclient和okhttp在feign中,client是一个非常重要的...

使用httpclient和okhttp

在feign中,client是一个非常重要的组件,feign最终发送request请求以及接收response响应都是由client组件来完成的。client在feign源码中是一个接口,在默认情况下,client的实现类是client.default。client.default是由httpurlconnection来实现网络请求的。另外,client还支持httpclient和okhttp来进行网络请求。

首先查看feignribbonclient的自动配置类feignribbonclientautoconfiguration,该类在程序启动的时候注入一些bean,其中注入了一个beanname为feignclient的client类型的bean。在省缺配置beanname为feignclient的bean的情况下,会自动注入client.default这个对象,跟踪client.default源码,client.default使用的网络请求框架是httpurlconnection,代码如下:

public static class default implements client {
        private final sslsocketfactory sslcontextfactory;
        private final hostnameverifier hostnameverifier;
 
        public default(sslsocketfactory sslcontextfactory, hostnameverifier hostnameverifier) {
            this.sslcontextfactory = sslcontextfactory;
            this.hostnameverifier = hostnameverifier;
        }
 
        public response execute(request request, options options) throws ioexception {
            httpurlconnection connection = this.convertandsend(request, options);
            return this.convertresponse(connection, request);
        }        
        ......//代码省略
}

这种情况下,由于缺乏连接池的支持,在达到一定流量的后服务肯定会出问题 。

使用httpclient

那么如何在feign中使用httpclient的框架呢?我们查看feignautoconfiguration.httpclientfeignconfiguration的源码:

    @configuration
    @conditionalonclass({apachehttpclient.class})
    @conditionalonmissingclass({"com.netflix.loadbalancer.iloadbalancer"})
    @conditionalonmissingbean({closeablehttpclient.class})
    @conditionalonproperty(
        value = {"feign.httpclient.enabled"},
        matchifmissing = true
    )
    protected static class httpclientfeignconfiguration {
        private final timer connectionmanagertimer = new timer("feignapachehttpclientconfiguration.connectionmanagertimer", true);
        @autowired(
            required = false
        )
        private registrybuilder registrybuilder;
        private closeablehttpclient httpclient;
 
        protected httpclientfeignconfiguration() {
        }
 
        @bean
        @conditionalonmissingbean({httpclientconnectionmanager.class})
        public httpclientconnectionmanager connectionmanager(apachehttpclientconnectionmanagerfactory connectionmanagerfactory, feignhttpclientproperties httpclientproperties) {
            final httpclientconnectionmanager connectionmanager = connectionmanagerfactory.newconnectionmanager(httpclientproperties.isdisablesslvalidation(), httpclientproperties.getmaxconnections(), httpclientproperties.getmaxconnectionsperroute(), httpclientproperties.gettimetolive(), httpclientproperties.gettimetoliveunit(), this.registrybuilder);
            this.connectionmanagertimer.schedule(new timertask() {
                public void run() {
                    connectionmanager.closeexpiredconnections();
                }
            }, 30000l, (long)httpclientproperties.getconnectiontimerrepeat());
            return connectionmanager;
        }
 
        @bean
        public closeablehttpclient httpclient(apachehttpclientfactory httpclientfactory, httpclientconnectionmanager httpclientconnectionmanager, feignhttpclientproperties httpclientproperties) {
            requestconfig defaultrequestconfig = requestconfig.custom().setconnecttimeout(httpclientproperties.getconnectiontimeout()).setredirectsenabled(httpclientproperties.isfollowredirects()).build();
            this.httpclient = httpclientfactory.createbuilder().setconnectionmanager(httpclientconnectionmanager).setdefaultrequestconfig(defaultrequestconfig).build();
            return this.httpclient;
        }
 
        @bean
        @conditionalonmissingbean({client.class})
        public client feignclient(httpclient httpclient) {
            return new apachehttpclient(httpclient);
        }
 
        @predestroy
        public void destroy() throws exception {
            this.connectionmanagertimer.cancel();
            if (this.httpclient != null) {
                this.httpclient.close();
            }
 
        }
    }

从代码@conditionalonclass({apachehttpclient.class})注解可知,只需要在pom文件上加上httpclient依赖即可。另外需要在配置文件中配置feign.httpclient.enabled为true,从@conditionalonproperty注解可知,这个配置可以不写,因为在默认情况下就为true:

<dependency>
    <groupid>io.github.openfeign</groupid>
    <artifactid>feign-httpclient</artifactid>
    <version>9.4.0</version>
</dependency>

使用okhttp

查看feignautoconfiguration.httpclientfeignconfiguration的源码:

    @configuration
    @conditionalonclass({okhttpclient.class})
    @conditionalonmissingclass({"com.netflix.loadbalancer.iloadbalancer"})
    @conditionalonmissingbean({okhttp3.okhttpclient.class})
    @conditionalonproperty({"feign.okhttp.enabled"})
    protected static class okhttpfeignconfiguration {
        private okhttp3.okhttpclient okhttpclient;
 
        protected okhttpfeignconfiguration() {
        }
 
        @bean
        @conditionalonmissingbean({connectionpool.class})
        public connectionpool httpclientconnectionpool(feignhttpclientproperties httpclientproperties, okhttpclientconnectionpoolfactory connectionpoolfactory) {
            integer maxtotalconnections = httpclientproperties.getmaxconnections();
            long timetolive = httpclientproperties.gettimetolive();
            timeunit ttlunit = httpclientproperties.gettimetoliveunit();
            return connectionpoolfactory.create(maxtotalconnections, timetolive, ttlunit);
        }
 
        @bean
        public okhttp3.okhttpclient client(okhttpclientfactory httpclientfactory, connectionpool connectionpool, feignhttpclientproperties httpclientproperties) {
            boolean followredirects = httpclientproperties.isfollowredirects();
            integer connecttimeout = httpclientproperties.getconnectiontimeout();
            boolean disablesslvalidation = httpclientproperties.isdisablesslvalidation();
            this.okhttpclient = httpclientfactory.createbuilder(disablesslvalidation).connecttimeout((long)connecttimeout, timeunit.milliseconds).followredirects(followredirects).connectionpool(connectionpool).build();
            return this.okhttpclient;
        }
 
        @predestroy
        public void destroy() {
            if (this.okhttpclient != null) {
                this.okhttpclient.dispatcher().executorservice().shutdown();
                this.okhttpclient.connectionpool().evictall();
            }
 
        }
 
        @bean
        @conditionalonmissingbean({client.class})
        public client feignclient(okhttp3.okhttpclient client) {
            return new okhttpclient(client);
        }
    }

同理,如果想要在feign中使用okhttp作为网络请求框架,则只需要在pom文件中加上feign-okhttp的依赖,代码如下:

<dependency>
    <groupid>io.github.openfeign</groupid>
    <artifactid>feign-okhttp</artifactid>
    <version>10.2.0</version>
</dependency>

openfeign替换为okhttp

pom中引入feign-okhttp

<dependency>
    <groupid>io.github.openfeign</groupid>
    <artifactid>feign-okhttp</artifactid>
</dependency>

在application.yml中配置okhttp

feign:
  httpclient:
    connection-timeout: 2000  #单位ms,默认2000
    max-connections: 200 #线程池最大连接数
  okhttp:
    enabled: true

经过上面设置已经可以使用okhttp了,因为在feignautoconfiguration中已实现自动装配

Feign 使用HttpClient和OkHttp方式

如果需要对okhttp做更精细的参数设置,那需要自定义okhttp的实现,可以模仿上图中的实现

以上为个人经验,希望能给大家一个参考,也希望大家多多支持。