目录
  • 使用httpclient和okhttp
    • 使用httpclient
    • 使用okhttp
  • openfeign替换为okhttp

使用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中已实现自动装配

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

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