Java:Apache HttpClient中HttpRoute用法的介绍

当使用Apache HttpClient组件时,经常会用到它的连接池组件。典型的代码如下:

复制代码
		PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager();
		connectionManager.setMaxTotal(httpConfig.getMaxPoolTotal());
		connectionManager.setDefaultMaxPerRoute(httpConfig.getMaxDefaultPerRoute());

		RequestConfig requestConfig = RequestConfig.custom() //
				.setConnectTimeout(httpConfig.getConnectTimeout()) //
				.setConnectionRequestTimeout(httpConfig.getConnectionRequestTimeout())//
				.setSocketTimeout(httpConfig.getSocketTimeout())//
				.build();

		HttpClientBuilder httpClientBuilder = HttpClientBuilder.create() //
				.setConnectionManager(connectionManager) //
				.setDefaultRequestConfig(requestConfig) //
				.useSystemProperties();

		HttpClient httpClient = httpClientBuilder.build();

其中maxTotal表示此连接池的最大连接数,defaultMaxPerRoute表示每路由最大连接数。这里主涉及到route在Apache HttpClient组件中是怎么使用的问题。先分析一下Apache HttpClient的源代码。以下使用的源代码版本4.5.14。

org.apache.http.impl.client.InternalHttpClient

可以看到这个方法传入的还是HttpHost,也就是请求地址,但下面就通过determineRoute方法生成了一个HttpRoute,并且后续也是使用HttpRoute。

org.apache.http.impl.conn.DefaultRoutePlanner

可以看到默认情况下,路由中的地址就是主机地址。

org.apache.http.impl.execchain.MainClientExec

这里也是使用HttpRoute。

org.apache.http.impl.conn.PoolingHttpClientConnectionManager

这里又开始使用HttpHost。

org.apache.http.impl.conn.DefaultHttpClientConnectionOperator

这里会解析hostName,如果通过hostName能解析出多个IP地址,则依次使用这些IP尝试创建socket,只要有一个能创建成功,则停止尝试。

从上述代码中可以看到,是按路由地址创建连接池的,如果路由地址中的主机地址可以解析成多个IP地址时,只会使用第一个可用的IP地址。

一般都是通过域名访问其它服务,而域名一般可以解析出多个IP,而域名默认情况下就是路由主机地址,只能为其中一个IP建立连接,且能创建的最大连接数就是defaultMaxPerRoute的值。这样远远达不到maxTotal的值。

当然,有一种办法是直接使用域名解析出的多个IP访问其它服务,这样每个IP就是一个路由,最后创建的总连接数就可以达到maxTotal的值。但这样的最大弊端是域名解析出的IP一般是动态的,可能会不但变化,程序中写死IP是非常不灵活的。

那有没有两全其美的办法,既使用域名访问其它服务,又使用域名解析后的IP作为路由创建连接池,使用连接数创建到最大值。办法是有的,只要实现一个RoutePlanner就行。

java 复制代码
public class TestRoutePlanner implements RoutePlanner {

    private final Random random = new Random();

    public HttpRoute determineRoute(HttpHost host, HttpRequest reqt, HttpContext ctx) {

        InetAddress[] addrs = InetAddress.getAllByName(host.getHostnName());
        
        int idx = random.mextInt(addrs.length);
        String hostAddr = addrs[idx]getHostAddress();

        HttpHost newHost = new HttpHost(hostAddr, host.getPort(), host.getSchemeName());

        return new HttpRoute(newHost, null, false);
    }
}

然后将TestRoutePlanner添加到HttpClient中。

java 复制代码
		HttpClientBuilder httpClientBuilder = HttpClientBuilder.create() //
				.setConnectionManager(connectionManager) //
				.setDefaultRequestConfig(requestConfig) //
				.setRoutePlanner(new TestRoutePlanner())//
				.useSystemProperties();

上述TestRoutePlanner写的比较简单,性能也不太好,只是不演示功能而已,实际使用时还需要进一步改造。

相关推荐
骑着蜗牛撵大象3273 分钟前
豆包 Seed 驱动的记账智能体:从拍票抽取到月报生成的全链路落地记录
java·前端·javascript·结构化输出·豆包seed·多模态识别·记账系统
憧憬成为java架构高手的小白12 分钟前
langchain4j手敲理解
java·langchain
北i42 分钟前
Dubbo 默认超时重试:把下游打雪崩的隐形放大器
开发语言·qt·dubbo
10mAh1 小时前
【Java】ArrayList 遍历删除为什么报错?三种写法与漏删复现
java·开发语言·windows
thefool1122661 小时前
多线程 4
java
wewowilling1 小时前
AI大模型开发--01Python基础(无废话)
开发语言·python·函数
小羊没烦恼!1 小时前
OS X 上使用.NET开发应用程序
开发语言·前端·数据库·人工智能·c#·策略模式
棉猴1 小时前
玩游戏学Python5-函数
开发语言·python·函数·玩游戏·游戏编程
Rain的Java大神之路1 小时前
[特殊字符]8年Java老兵转型AI Agent:90%的人挂在同一个坑,根本不用学Python!(万字实战复盘,建议收藏)
java·数据库·人工智能·后端·python·spring·ai编程
高级程序源2 小时前
springboot大学生体测系统72170-计算机课程设计、毕业设计
java·vue.js·spring boot·后端·python·django·课程设计