1.概述

在本文中,我们将介绍HttpClient 4中连接管理的基础知识。

我们将介绍BasichttpclientConnectionManager.PoolingHttpClientConnectionManager强制执行安全,协议兼容,有效地使用HTTP连接。

2.这BasichttpclientConnectionManager.用于低电平,单螺纹连接

BasichttpclientConnectionManager.自httpclient 4.3.3是最简单的HTTP Connection Manager的实现。它用于创建和管理单个连接,该连接只能一次由一个线程使用。

进一步阅读:

高级的HttpClient配置

高级用例的HttpClient配置。

HttpClient 4 -发送自定义Cookie

如何使用Apache HttpClient 4发送自定义cookie。

HttpClient和SSL

使用SSL配置HttpClient的示例。

例2.1。获得低级连接的连接请求(httpclientConnection.

BasicHttpClientConnectionManager connManager = new BasicHttpClientConnectionManager();HttpRoute route = new HttpRoute(new HttpHost("www.金宝搏188体育baeldung.com", 80));ConnectionRequest connRequest = connManager。requestConnection(路线,null);

requestConnection方法从管理器获取特定的连接池路线连接。这路线参数指定目标主机或目标主机本身的“代理跳”路由。

可以使用httpclientConnection.直接,但请记住这种低级方法是冗长的,难以管理。低级连接对于访问套接字和连接数据(例如超时和目标主机信息)非常有用,但是对于标准执行httpclient是一个更容易的API来锻炼身体。

3.使用PoolingHttpClientConnectionManager获取和管理多线程连接池

PoolingHttpClientConnectionManager将为我们使用的每个路由或目标主机创建和管理连接池。并发池的默认大小连接可以由经理开放2为每个路线或目标主机,20总打开连接。首先 - 让我们来看看如何在一个简单的httpclient上设置此连接管理器:

例3.1。在httpclient上设置poolinghttpclientconnectionManager

HttpClientConnectionManager poolingConnManager = new PoolingHttpClientConnectionManager();CloseableHttpClient client = httpclient .custom().setConnectionManager(poolingConnManager) .build();客户端。执行(新HttpGet (" / "));.getLeased assertTrue (poolingConnManager.getTotalStats () () = = 1);

下一步 - 让我们看看如何在两个不同的线程中运行的两个httpclients如何使用相同的连接管理器:

例3.2。使用两个httpclients连接到一个目标主机

httpget get1 = new httpget(“/”);httpget get2 = new httpget(“http://google.com”);PoolingHttpClientConnectionManager connManager = new PoolingHttpClientConnectionManager();CloseAbrehttpclient client1 = httpclients.custom()。setConnectionManager(ConnManager).build();Closeablehttpclient client2 = httpclient.custom()。setConnectionManager(ConnManager).build();multihttpclientconnnthread thread1 = new multihttpclientconnnthread(client1,get1);multihttpclientconnnthread thread2 = new multihttpclientconnnthread(client2,get2);thread1.start();thread2.start();thread1.join(); thread2.join();

注意我们正在使用一个非常简单的自定义线程实现- 这里是:

例3.3。自定义线程执行A.GET请求

公共类MultiHTTPClientConnnThread扩展线程{私有关闭HTTPClient客户端;私有httpget获取;//标准构造函数公共void run(){try {httpresponse response = client.execute(get);entityutils.consume(response.getentity());catch(clientProtocolException ex){} catch(ioException ex){}}}

通知EntityUtils.consume(response.getentity)呼叫 - 需要消耗响应(实体)的整个内容,以便管理员可以将连接释放回池

4.配置Connection Manager

池连接管理器的默认值选择得很好,但是—根据您的用例—可能太小了。那么,让我们来看看如何配置:

  • 连接总数
  • 每(任何)路由的最大连接数
  • 每条特定路由的最大连接数

例4.1。增加可以打开和管理超出默认限制的连接数

PoolingHttpClientConnectionManager connManager = new PoolingHttpClientConnectionManager();connManager.setMaxTotal (5);connmanager.setdefaultmaxperroute(4);httphost host = new httpost(“www.b金宝搏188体育aeldung.com”,80);connmanager.setmaxperroute(新的httproute(主机),5);

让我们回顾一下API:

  • setmaxtotal(int max):设置总打开连接数的最大值。
  • setDefaultMaxPerRoute (int马克斯):设置每条路由的最大并发连接数,默认为2。
  • setMaxPerRoute (int马克斯):将并发连接的总数设置为特定路由,默认为2。

所以,不改变默认值,我们将达到连接管理器的极限很简单-让我们看看它是怎样的:

例4.2。使用线程执行连接

httpget get = new httpget(“http://www.金宝搏188体育baeldung.com”);PoolingHttpClientConnectionManager connManager = new PoolingHttpClientConnectionManager();Closeablehttpclient client = httpclients.custom()。setConnectionManager(ConnManager).Build();multihttpclientconnnthread thread1 = new multihttpclientconnnthread(客户端,get);multihttpclientconnnthread thread2 = new multihttpclientconnnthread(客户端,get);multihttpclientconnnthread thread3 = new multihttpclientconnnthread(客户端,get);thread1.start();thread2.start();thread3.start(); thread1.join(); thread2.join(); thread3.join();

我们已经讨论过了,每个主机连接限制为2默认。所以,在这个例子中,我们试图有3个线程向同一个主机发出3个请求,但只有2个连接将并行分配。

让我们来看看日志 - 我们有三个线程运行,但只有2个租用连接:

[Thread-0] INFO o.b.h.c.MultiHttpClientConnThread - Before - Leased Connections = 0 [Thread-1] INFO o.b.h.c.MultiHttpClientConnThread - Before - Leased Connections = 0 [Thread-2] INFO o.b.h.c.MultiHttpClientConnThread - Before - Leased Connections = 0 [Thread-2] INFO o.b.h.c.MultiHttpClientConnThread - After - Leased Connections = 2 [Thread-0] INFO o.b.h.c.MultiHttpClientConnThread - After - Leased Connections = 2

5.连接维生的策略

引用HttpClient 4.3.3。参考:“如果维生报头不存在于响应中,httpclient假定连接可以无限期地保持活动。”(请参阅HttpClient参考)。

要解决这个问题,并且能够管理死亡的连接,我们需要定制的策略实现并将其建立到httpclient

例5.1。一个自定义的生存策略

ConnectionKeepAliveStrategy myStrategy = new ConnectionKeepAliveStrategy() {@Override public long getKeepAliveDuration(HttpResponse response, HttpContext context) {HeaderElementIterator它= new BasicHeaderElementIterator (response. headeriterator (HTTP.CONN_KEEP_ALIVE));while (it.hasNext()) {HeaderElement he = it.nextElement();String param = he.getName();String值= he.getValue();If (value != null && param.)equalsignorrecase ("timeout")) {return Long.parseLong(value) * 1000;}}返回5 * 1000;}};

此策略将首先尝试应用主机的维生在标题中陈述的策略。如果该信息没有出现在响应头中,它将保持活动连接5秒。

现在 - 让我们创造具有此自定义战略的客户

PoolingHttpClientConnectionManager connManager = new PoolingHttpClientConnectionManager();Closeablehttpclient client = httpclient.custom().setkeepalivestrategy(mystrategy).setConnectionManager(ConnManager).build();

6.连接持久性/重用

HTTP/1.1规范指出,如果连接没有被关闭,那么它可以被重用——这就是所谓的连接持久性。

一旦连接通过管理器发布,它会保持打开以便重复使用。使用时BasichttpclientConnectionManager,它只能管理一个连接,必须释放连接之前,它被再次租赁回来:

例6.1。BasichttpclientConnectionManager.连接重复使用

basichttpclientConnectionManager BasicConnManager = New BasichTtpClientConnectionManager();httpclientcontext上下文= httpclientcontext.create();//低级别httproute路由= new httproute(新的httposte(“www.soft30t.com”,8金宝搏188体育0));connectionRequest connrequest = basicconnmanager.requestConnection(路由,null);httpclientconnection conn = connrequest.get(10,tumneUnit.seconds);BasicConnManager.Connect(Conn,Route,1000,上下文);BasicConnmanager.routeComplete(Conn,Route,Context);httprequestexecutor exerequest = new httprequestexecutor();context.settargethost((新的httphost(“www.ba金宝搏188体育eldung.com”,80))));httpget get = new httpget(“http://www.金宝搏188体育baeldung.com”); exeRequest.execute(get, conn, context); basicConnManager.releaseConnection(conn, null, 1, TimeUnit.SECONDS); // high level CloseableHttpClient client = HttpClients.custom() .setConnectionManager(basicConnManager) .build(); client.execute(get);

让我们看看发生了什么。

首先,请注意,我们首先使用一个低级连接,以便我们能够完全控制何时释放连接,然后使用HttpClient的一个普通的高级连接。复杂的底层逻辑在这里不是很相关——我们唯一关心的是金宝搏官网188be释放调用。这将释放唯一可用的连接,并允许重用它。

然后,客户端同时执行G​​ET请求。如果我们跳过释放连接,我们将从httpclient获取IllegalStateException:

在o.a.h.i.c.BasicHttpClientConnectionManager.getConnection (BasicHttpClientConnectionManager.java:248)中仍然分配连接。

请注意,现有连接未关闭,刚刚发布,然后由第二个请求重新使用。

与上面的例子相反,PoolingHttpClientConnectionManager允许连接透明地重新使用,无需隐式释放连接:

例6.2。PoolingHttpClientConnectionManager重新使用与线程的连接

HttpGet get = new HttpGet("http://echo.200please.com");PoolingHttpClientConnectionManager connManager = new PoolingHttpClientConnectionManager();connManager.setDefaultMaxPerRoute (5);connManager.setMaxTotal (5);CloseableHttpClient client = httpclient .custom() .setConnectionManager(connManager) .build();MultiHttpClientConnThread[] threads = new MultiHttpClientConnThread[10];For (int I = 0;我< threads.length;i++){thread [i] = new MultiHttpClientConnThread(client, get, connManager);} for (MultiHttpClientConnThread thread: threads) {thread.start(); } for (MultiHttpClientConnThread thread: threads) { thread.join(1000); }

上面的例子有10个线程,执行10个请求,但只共享5个连接。

当然,这个例子依赖于服务器的维生超时。为确保连接在被重用之前不会失效,建议配置客户与A.维生策略(见例5.1。)。

7.使用Connection Manager配置超时 - 套接字超时

配置Connection Manager配置时可以设置的唯一超时是套接字超时:

例7.1。设置“Socket超时时间”为“5秒”

HttpRoute route = new HttpRoute(new HttpHost("www.金宝搏188体育baeldung.com", 80));PoolingHttpClientConnectionManager connManager = new PoolingHttpClientConnectionManager();SocketConfig.custom connManager.setSocketConfig (route.getTargetHost()()。setSoTimeout (5000) .build ());

有关HttpClient -中超时的更深入讨论看到这个

8.连接被驱逐

连接逐出用于检测空闲和过期的连接并关闭它们;有两种方法可以做到这一点。

  1. 依赖于httpclien.T来检查在执行请求之前连接是否过期。这是一个昂贵的选择,并不总是可靠的。
  2. 创建一个监视器线程以关闭空闲和/或封闭连接。

例8.1。设置httpclient检查陈旧的连接

PoolingHttpClientConnectionManager connManager = new PoolingHttpClientConnectionManager();Closeablehttpclient client = httpclient.custom()。setDefaultRequestConfig(RequestConfig.Custom()。SetStaleConnectionCheckEnenabled(true).build()).build()).setConnectionManager(ConnManager).build();

例8.2。使用陈旧的连接监视器线程

PoolingHttpClientConnectionManager connManager = new PoolingHttpClientConnectionManager();CloseableHttpClient client = httpclient .custom() .setConnectionManager(connManager).build();IdleConnectionMonitorThread staleMonitor = new IdleConnectionMonitorThread(connManager);staleMonitor.start ();staleMonitor.join (1000);

idleconnectionmonitorthread.类别如下:

公共类IDleConnectionMonitorthRead扩展线程{私有最终HTTPCLIENTCONNECTIONMAGER CONNMGR;私人挥发性布尔关机;公共IdleConnectionMonitorthRead(poolinghttpclientconnectionManager Connmgr){super();this.connmgr = connmgr;@override public void run(){try {while(!shutdown){synchronized(这){wait(1000);connmgr.closeexpiredconnections();connmgr.closeidleconnections(30,tumneUnit.seconds);catch(InterruptedException ex){shutdown();public void shutdown(){shutdown = true;同步(此){NotifyAll(); } } }

9.连接结束

可以优雅地关闭连接(尝试在关闭之前刷新输出缓冲区)或强有力地通过呼叫关闭方法(输出缓冲区未刷新)。

要正确关闭连接,我们需要做以下所有事情:

  • 使用并关闭响应(如果可关闭)
  • 关闭客户端
  • 关闭并关闭连接管理器

例8.1。关闭连接和释放资源

connmanager = new poolinghttpclientConnectionManager();CloseableHttpClient client = httpclient .custom() .setConnectionManager(connManager).build();httpget get = new httpget(“http://google.com”);closeablehttpresponse响应= client.execute(get);entityutils.consume(response.getentity());Response.close();client.close();connmanager.close();

如果管理器被关闭而连接没有被关闭-所有的连接将被关闭,所有的资源将被释放。

重要的是要记住,这不会刷新现有连接中可能正在进行的任何数据。

10.结论

在本文中,我们讨论了如何使用HttpClient的HTTP连接管理API来处理管理连接的整个过程-从打开和分配它们,通过管理它们的并发使用多个代理,最终关闭它们。

我们看到了BasichttpclientConnectionManager.是一个简单的解决方案来处理单个连接,以及如何管理低级连接。我们也看到了如何PoolingHttpClientConnectionManager结合了httpclientAPI提供了HTTP连接的高效且符合协议的使用。

通用的底部

使用Spring 5和Spring Boot 2开始,通过学习的春天课程:

>>看看这个课程
6.评论
最老的
最新
内联反馈
查看所有评论
评论在本文上关闭!