HttpClient kapcsolatkezelés
1. Áttekintés
Ebben a cikkben áttekintjük a HttpClient 4 kapcsolatkezelésének alapjait.
Kitérünk a használatára BasichttpClientConnectionManager és PoolingHttpClientConnectionManager a HTTP-kapcsolatok biztonságos, protokollnak megfelelő és hatékony használatának kikényszerítése.
2. A BasicHttpClientConnectionManager alacsony szintű, egy menetes csatlakozáshoz
A BasicHttpClientConnectionManager a HttpClient 4.3.3 óta elérhető, mint a HTTP-kapcsolatkezelő legegyszerűbb megvalósítása. Egyetlen kapcsolat létrehozására és kezelésére szolgál, amelyet egyszerre csak egy szál használhat.
2.1. Példa Csatlakozási kérelem beszerzése alacsony szintű csatlakozáshoz (HttpClientConnection)
BasicHttpClientConnectionManager connManager = új BasicHttpClientConnectionManager (); HttpRoute útvonal = új HttpRoute (új HttpHost ("www.baeldung.com", 80)); ConnectionRequest connRequest = connManager.requestConnection (útvonal, null);
A requestConnection A módszer a menedzsertől kap egy adott kapcsolat kapcsolatait útvonal csatlakozni. A útvonal A paraméter megadja a „proxy ugrás” útvonalát a célállomásig, vagy maga a célállomásig.
Lehetőség van egy kérés végrehajtására egy HttpClientConnection közvetlenül, de ne feledje, hogy ez az alacsony szintű megközelítés bőbeszédű és nehezen kezelhető. Az alacsony szintű kapcsolatok hasznosak a socket és a csatlakozási adatok eléréséhez, például az időkorlátokhoz és a célállomás információkhoz, de a szokásos végrehajtásokhoz a HttpClient egy sokkal könnyebb API, amellyel szemben lehet dolgozni.
3. A PoolingHttpClientConnectionManager többszálas kapcsolatok készletének megszerzése és kezelése
A PoolingHttpClientConnectionManager létrehoz egy kapcsolatkészletet és kezel minden egyes általunk használt útvonalat vagy célgazdát. Az egyidejű készlet alapértelmezett mérete kapcsolatok amelyet a menedzser megnyithat 2 minden útvonalhoz vagy célgazdához, és 20 összesen nyitott kapcsolatok. Először - nézzük meg, hogyan állíthatja be ezt a kapcsolatkezelőt egy egyszerű HttpClient-en:
3.1. Példa A PoolingHttpClientConnectionManager beállítása HttpClienten
HttpClientConnectionManager poolingConnManager = új PoolingHttpClientConnectionManager (); CloseableHttpClient kliens = HttpClients.custom (). SetConnectionManager (poolingConnManager) .build (); client.execute (új HttpGet ("/")); assertTrue (poolingConnManager.getTotalStats (). getLeased () == 1);
Következő - nézzük meg, hogyan használhatja ugyanazt a kapcsolatkezelőt két, különböző szálon futó HttpClients:
3.2. Példa Két HttpClients segítségével csatlakozhat egy-egy célgazdához
HttpGet get1 = új HttpGet ("/"); HttpGet get2 = new HttpGet ("// google.com"); PoolingHttpClientConnectionManager connManager = új PoolingHttpClientConnectionManager (); CloseableHttpClient client1 = HttpClients.custom (). SetConnectionManager (connManager) .build (); CloseableHttpClient client2 = HttpClients.custom (). SetConnectionManager (connManager) .build (); MultiHttpClientConnThread thread1 = új MultiHttpClientConnThread (client1, get1); MultiHttpClientConnThread thread2 = új MultiHttpClientConnThread (client2, get2); thread1.start (); thread2.start (); szál1.csatlakozzon (); szál2.csatlakozzon ();
Figyeljük meg, hogy használjuk egy nagyon egyszerű egyéni szál megvalósítása - itt van:
3.3. Példa Egyéni szál A. Végrehajtása GET kérés
public class MultiHttpClientConnThread kiterjeszti a Thread {private CloseableHttpClient klienst; privát HttpGet get; // standard konstruktorok public void run () {try {HttpResponse response = client.execute (get); EntityUtils.consume (response.getEntity ()); } catch (ClientProtocolException ex) {} catch (IOException ex) {}}}
Figyelje meg aEntityUtils.consume (response.getEntity) hívás - a válasz (entitás) teljes tartalmának elfogyasztásához szükséges, hogy a menedzser megtehesse engedje vissza a kapcsolatot a medencéhez.
4. Konfigurálja a Connection Manager alkalmazást
A pooling kapcsolatkezelő alapértelmezett beállításai jól megválasztottak, de - felhasználási esetétől függően - túl kicsiek lehetnek. Tehát - nézzük meg, hogyan konfigurálhatjuk:
- a kapcsolatok teljes száma
- az útvonalakonkénti kapcsolatok maximális száma
- a kapcsolatok maximális száma egyetlen, meghatározott útvonalon
4.1. Példa Az alapértelmezett korlátokon túl megnyitható és kezelhető kapcsolatok számának növelése
PoolingHttpClientConnectionManager connManager = új PoolingHttpClientConnectionManager (); connManager.setMaxTotal (5); connManager.setDefaultMaxPerRoute (4); HttpHost host = new HttpHost ("www.baeldung.com", 80); connManager.setMaxPerRoute (új HttpRoute (host), 5);
Tegyük át az API-t:
- setMaxTotal (int max): Állítsa be az összes nyitott kapcsolat maximális számát.
- setDefaultMaxPerRoute (int max): Állítsa be az egyidejű kapcsolatok maximális számát útvonalonként, amely alapértelmezés szerint 2.
- setMaxPerRoute (int max): Állítsa be az egyidejű kapcsolatok teljes számát egy adott útvonalhoz, amely alapértelmezés szerint 2.
Tehát az alapértelmezés megváltoztatása nélkül, elérjük a kapcsolatkezelő határait elég könnyen - nézzük meg, hogy néz ki:
4.2. Példa Szálak használata a kapcsolatok végrehajtásához
HttpGet get = new HttpGet ("// www.baeldung.com"); PoolingHttpClientConnectionManager connManager = új PoolingHttpClientConnectionManager (); CloseableHttpClient kliens = HttpClients.custom (). setConnectionManager (connManager) .build (); MultiHttpClientConnThread thread1 = új MultiHttpClientConnThread (kliens, get); MultiHttpClientConnThread thread2 = új MultiHttpClientConnThread (kliens, get); MultiHttpClientConnThread thread3 = új MultiHttpClientConnThread (kliens, get); thread1.start (); thread2.start (); thread3.start (); szál1.csatlakozzon (); szál2.csatlakozzon (); szál3.csatlakozzon ();
Amint már megbeszéltük, az állomásonkénti csatlakozási korlát 2 alapértelmezés szerint. Tehát ebben a példában 3 szálat próbálunk elkészíteni 3 kérés ugyanahhoz a gazdagéphez, de csak 2 kapcsolatot osztanak ki párhuzamosan.
Vessünk egy pillantást a naplókra - három szál fut, de csak 2 bérelt kapcsolat van:
[Thread-0] INFO obhcMultiHttpClientConnThread - Before - Bérelt kapcsolatok = 0 [Thread-1] INFO obhcMultiHttpClientConnThread - Before - Bérelt kapcsolatok = 0 [Thread-2] INFO obhcMultiHttpClientConnThread - 0 - Before - INFO obhcMultiHttpClientConnThread - After - Bérelt kapcsolatok = 2 [Thread-0] INFO obhcMultiHttpClientConnThread - After - Bérelt kapcsolatok = 2
5. Connection Keep-Alive stratégia
Idézi a HttpClient 4.3.3. hivatkozás: „Ha a Életben tartani
fejléc nincs a válaszban, HttpClient feltételezi, hogy a kapcsolatot a végtelenségig életben lehet tartani. ” (Lásd a HttpClient referenciát).
Ahhoz, hogy ezt megkerüljük, és képesek legyünk kezelni a holt kapcsolatokat, testreszabott stratégia-megvalósításra van szükségünk, és beépítjük a HttpClient.
5.1. Példa Egyéni életben tartási stratégia
ConnectionKeepAliveStrategy myStrategy = new ConnectionKeepAliveStrategy () {@Orride public long getKeepAliveDuration (HttpResponse response, HttpContext context) {HeaderElementIterator it = new BasicHeaderElementIterator (response.headerIterator (HTTP.Eladó) while (it.hasNext ()) {HeaderElement he = it.nextElement (); Karakterlánc param = he.getName (); Karakterlánc értéke = he.getValue (); if (érték! = null && param.equalsIgnoreCase ("timeout")) {return Long.parseLong (érték) * 1000; }} visszatérés 5 * 1000; }};
Ez a stratégia először megpróbálja alkalmazni a gazdagépet Életben tartani a fejlécben megfogalmazott irányelv. Ha ez az információ nincs a válasz fejlécében, akkor 5 másodpercig életben tartja a kapcsolatokat.
Most - alkossunk kliens ezzel az egyedi stratégiával:
PoolingHttpClientConnectionManager connManager = új PoolingHttpClientConnectionManager (); CloseableHttpClient kliens = HttpClients.custom () .setKeepAliveStrategy (myStrategy) .setConnectionManager (connManager) .build ();
6. A kapcsolat tartóssága / újrafelhasználása
A HTTP / 1.1 Spec azt állítja, hogy a kapcsolatok újból felhasználhatók, ha még nem voltak bezárva - ezt kapcsolati perzisztenciának nevezzük.
Amint a menedzser feloldotta a kapcsolatot, az nyitva marad újrafelhasználás céljából. Ha a BasicHttpClientConnectionManager, amely csak egyetlen kapcsolatot képes elrontani, a kapcsolatot újra fel kell szabadítani, mielőtt újból bérbe adnák:
6.1. Példa BasicHttpClientConnectionManagerKapcsolat újrafelhasználása
BasicHttpClientConnectionManager basicConnManager = új BasicHttpClientConnectionManager (); HttpClientContext context = HttpClientContext.create (); // alacsony szintű HttpRoute útvonal = új HttpRoute (új HttpHost ("www.baeldung.com", 80)); ConnectionRequest connRequest = basicConnManager.requestConnection (útvonal, null); HttpClientConnection conn = connRequest.get (10, TimeUnit.SECONDS); basicConnManager.connect (összeköttetés, útvonal, 1000, kontextus); basicConnManager.routeComplete (kapcsolat, útvonal, kontextus); HttpRequestExecutor exeRequest = új HttpRequestExecutor (); context.setTargetHost ((új HttpHost ("www.baeldung.com", 80))); HttpGet get = new HttpGet ("// www.baeldung.com"); exeRequest.execute (get, conn, context); basicConnManager.releaseConnection (csatlakozás, null, 1, TimeUnit.SECONDS); // magas szintű CloseableHttpClient kliens = HttpClients.custom () .setConnectionManager (basicConnManager) .build (); client.execute (get);
Vessünk egy pillantást a történésekre.
Először - vegye észre, hogy először alacsony szintű kapcsolatot használunk, csak azért, hogy teljes ellenőrzésünk legyen a kapcsolat felszabadulásakor, majd egy normál magasabb szintű kapcsolatot egy HttpClient-tel. A bonyolult alacsony szintű logika itt nem nagyon releváns - az egyetlen dolog, ami érdekel, az a releaseConnection hívás. Ez felszabadítja az egyetlen elérhető kapcsolatot, és lehetővé teszi újrafelhasználását.
Ezután az ügyfél ismét sikeresen végrehajtja a GET kérést. Ha kihagyjuk a kapcsolat feloldását, akkor egy IllegalStateExceptiont kapunk a HttpClient-től:
java.lang.IllegalStateException: A kapcsolatot továbbra is lefoglalják az o.a.h.u.Asserts.check (Asserts.java:34) címen az o.a.h.i.c.BasicHttpClientConnectionManager.getConnection (BasicHttpClientConnectionManager.java:248)
Ne feledje, hogy a meglévő kapcsolat nincs lezárva, csak felszabadul, majd a második kérelem újra felhasználja.
A fenti példával ellentétben a PoolingHttpClientConnectionManager lehetővé teszi a kapcsolat újrafelhasználását átláthatóan anélkül, hogy implicit módon kellene feloldani a kapcsolatot:
6.2. PéldaPoolingHttpClientConnectionManager: A szálakkal való kapcsolatok újrafelhasználása
HttpGet get = new HttpGet ("// echo.200please.com"); PoolingHttpClientConnectionManager connManager = új PoolingHttpClientConnectionManager (); connManager.setDefaultMaxPerRoute (5); connManager.setMaxTotal (5); CloseableHttpClient kliens = HttpClients.custom () .setConnectionManager (connManager) .build (); MultiHttpClientConnThread [] szálak = új MultiHttpClientConnThread [10]; for (int i = 0; i <szálak.hossz; i ++) {szálak [i] = új MultiHttpClientConnThread (kliens, get, connManager); } a (MultiHttpClientConnThread szál: szálak) {thread.start (); } a (MultiHttpClientConnThread szál: szálak) {thread.join (1000); }
A fenti példa 10 szálat tartalmaz, 10 kérést hajt végre, de csak 5 kapcsolatot oszt meg.
Természetesen ez a példa a szerverre támaszkodik Életben tartani időtúllépés. Annak érdekében, hogy az újbóli felhasználás előtt a kapcsolatok ne haljanak meg, javasoljuk a ügyfél val,-vel Életben tartani stratégiát (lásd az 5.1. példát).
7. Időkorlátok konfigurálása - Socket időtúllépés a Connection Manager használatával
Az egyetlen időtúllépés, amelyet a kapcsolatkezelő konfigurálásakor lehet beállítani, a socket időtúllépése:
7.1. Példa A Socket Timeout beállítása 5 másodpercre
HttpRoute útvonal = new HttpRoute (új HttpHost ("www.baeldung.com", 80)); PoolingHttpClientConnectionManager connManager = új PoolingHttpClientConnectionManager (); connManager.setSocketConfig (route.getTargetHost (), SocketConfig.custom (). setSoTimeout (5000) .build ());
Az időkorlátok mélyebb megvitatásához a HttpClient-en - lásd ezt.
8. Csatlakozás kilakoltatása
A kapcsolat kilakoltatása megszokta tétlen és lejárt kapcsolatok észlelése és bezárása; ennek két lehetősége van.
- Támaszkodva a HttpClient a kérelem végrehajtása előtt ellenőrizze, hogy a kapcsolat elavult-e. Ez egy drága lehetőség, amely nem mindig megbízható.
- Hozzon létre egy monitor szálat a tétlen és / vagy zárt kapcsolatok bezárásához.
8.1. Példa A HttpClient hogy ellenőrizze az elavult kapcsolatokat
PoolingHttpClientConnectionManager connManager = új PoolingHttpClientConnectionManager (); CloseableHttpClient ügyfél = HttpClients.custom (). SetDefaultRequestConfig (RequestConfig.custom (). SetStaleConnectionCheckEnabled (true) .build ()) .setConnectionManager (connManager) .build ();
8.2. Példa Elavult kapcsolatfigyelő szál használata
PoolingHttpClientConnectionManager connManager = új PoolingHttpClientConnectionManager (); CloseableHttpClient kliens = HttpClients.custom () .setConnectionManager (connManager) .build (); IdleConnectionMonitorThread staleMonitor = new IdleConnectionMonitorThread (connManager); staleMonitor.start (); staleMonitor.join (1000);
A IdleConnectionMonitorThreadosztály az alábbiakban szerepel:
public class IdleConnectionMonitorThread kiterjeszti a Threadot {private final HttpClientConnectionManager connMgr; privát volatilis logikai leállítás; public IdleConnectionMonitorThread (PoolingHttpClientConnectionManager connMgr) {super (); this.connMgr = connMgr; } @Orride public void run () {try {while (! Shutdown) {synchronized (this) {wait (1000); connMgr.closeExpiredConnections (); connMgr.closeIdleConnections (30, TimeUnit.SECONDS); }}} catch (InterruptedException ex) {shutdown (); }} public void shutdown () {shutdown = true; szinkronizált (ez) {noticeAll (); }}}
9. Csatlakozás lezárása
A kapcsolat kecsesen lezárható (a kimeneti puffert a becsukás előtt le kell öblíteni), vagy erőteljesen, a Leállitás módszer (a kimeneti puffert nem öblítik le).
A kapcsolatok megfelelő lezárásához a következőket kell elvégeznünk:
- fogyasztani és bezárni a választ (ha zárható)
- zárja be az ügyfelet
- zárja be és állítsa le a kapcsolatkezelőt
8.1. Példa Kapcsolat bezárása és erőforrások felszabadítása
connManager = new PoolingHttpClientConnectionManager (); CloseableHttpClient kliens = HttpClients.custom () .setConnectionManager (connManager) .build (); HttpGet get = new HttpGet ("// google.com"); CloseableHttpResponse response = client.execute (get); EntityUtils.consume (response.getEntity ()); válasz.zár (); client.close (); connManager.close ();
Ha a menedzsert úgy állítják le, hogy a kapcsolatok már nincsenek lezárva - az összes kapcsolat lezárul és az összes erőforrás felszabadul.
Fontos szem előtt tartani, hogy ezzel nem törlődnek azok az adatok, amelyek a meglévő kapcsolatoknál esetleg folyamatban voltak.
10. Következtetés
Ebben a cikkben megvitattuk, hogyan lehet kezelni a HttpClient HTTP Connection Management API-ját a kapcsolatok kezelésének teljes folyamata - a kinyitástól és a kiosztástól kezdve a több ügynök egyidejű használatának kezeléséig, a végleges bezárásig.
Láttuk, hogy a BasicHttpClientConnectionManager egy egyszerű megoldás az egyes kapcsolatok kezelésére, és arra, hogyan tudja kezelni az alacsony szintű kapcsolatokat. Azt is láttuk, hogy a PoolingHttpClientConnectionManager kombinálva a HttpClient Az API biztosítja a HTTP-kapcsolatok hatékony és protokollnak megfelelő használatát.