Saya baru -baru ini menggunakan httpclient dan melihat dokumen resmi: implementasi httpClient diharapkan aman. Disarankan bahwa contoh yang sama dari kelas ini digunakan kembali untuk beberapa eksekusi permintaan. Sarana terjemahan: Implementasi HTTPClient aman-utas dan dapat menggunakan kembali instance yang sama untuk menjalankan beberapa permintaan. Ketika kita menemukan deskripsi ini, kita harus berpikir bahwa httpClient perlu dienkapsulasi. Karena digunakan boot pegas, kami akan menggabungkan boot pegas untuk merangkum httpclient.
1. Permintaan Retry Handler (Permintaan Pemrosesan Retry)
Untuk membuat mekanisme pengecualian khusus mulai berlaku, antarmuka HTTPRequestRetryHandler perlu diimplementasikan, kode tersebut adalah sebagai berikut:
impor java.io.ioException; impor java.io.interruptedioException; impor java.net.unknownhostException; impor javax.net.ssl.sslexception; impor javax.net.ssl.sslhandshakeException; impor org.apache.http.httpenclosingRequest; impor org.apache.http.httpRequest; impor org.apache.http.nohttpresponseException; impor org.apache.http.client.httpRequestRetryHandler; impor org.apache.http.client.protocol.httpClientContext; impor org.apache.http.conn.connectTimeOutException; impor org.apache.http.protocol.httpcontext; impor org.springframework.beans.factory.annotation.value; impor org.springframework.context.annotation.bean; impor org.springframework.context.annotation.configuration; /** * Description: HttpClient's retry processing mechanism*/ @Configuration public class MyhttpRequestRetryHandler { @Value("${httpclient.config.retryTime}")// Here it is recommended to use @ConfigurationProperties(prefix="httpclient.config") method to facilitate reuse of private int retryTime; @Bean public httpRequestRetryHandler httpRequestRetryHandler () {// Permintaan coba lagi int int retrytime = this.retrytime; return new HttpRequestRetryHandler() { public boolean retryRequest(IOException exception, int executionCount, HttpContext context) { // Do not retry if over max retry count, if the number of retrys exceeds retryTime, the request will no longer be retryed if (executionCount >= retryTime) { return false; } // Server memecahkan pengecualian koneksi klien jika (contoh pengecualian dari nohttpresponseException) {return true; } // Timeout Timeout Retry if (Exception Instanceof InterruptedioException) {return true; } // host yang tidak diketahui if (pengecualian contoh dari unknownHostException) {return false; } // Koneksi ditolak jika (pengecualian ConnectTimeOutException) {return false; } // SSL Handshake Exception if (Exception instance dari Sslexception) {return false; } HttpClientContext clientContext = httpClientContext.Adapt (konteks); HttpRequest request = clientContext.getRequest (); if (! (Permintaan contoh dari httpentityenclosingRequest)) {return true; } return false; }}; }} 2. Pooling Connection Manager (Manajemen Koleksi Koneksi)
PoolingHttpClientConnectionManager digunakan untuk mengelola kumpulan koneksi klien dan dapat menyediakan layanan untuk permintaan dari beberapa utas. Kodenya adalah sebagai berikut:
impor org.apache.http.config.registry; impor org.apache.http.config.registryBuilder; impor org.apache.http.conn.socket.connectionCocketFactory; impor org.apache.http.conn.socket.layeredConnectionCocketFactory; impor org.apache.http.conn.socket.plainConnectionCocketFactory; impor org.apache.http.conn.ssl.sslconnectionCocketFactory; impor org.apache.http.impl.conn.poolinghttpClientConnectionManager; impor org.springframework.beans.factory.annotation.value; impor org.springframework.context.annotation.bean; impor org.springframework.context.annotation.configuration; @Configuration Public Class MyPoolingHttpClientConnectionManager { / *** Jumlah maksimum koneksi di kumpulan koneksi* / @Value ("$ {httpclient.config.connmaxtotal}") inter connmaxtotal pribadi = 20; / ** * */ @value ("$ {httpclient.config.maxperroute}") private int maxperroute = 20; / ** * Waktu bertahan hidup koneksi, unit adalah s */ @value ("$ {httpclient.config.timetolive}") private int timetolive = 60; @Bean PoolingHttpClientConnectionManager PoolingClientConnectionManager () {poolingHttpClientConnectionManager PoolHttpcconnManager = PoolingHttpClientConnectionManager baru (60, timeunit.seconds); // jumlah maksimum koneksi poolhttpcconnManager.setmaxtotal (this.connmaxtotal); // rute Radix poolhttpcconnManager.setDefaultMaxperroute (this.maxperroute); Return PoolHttpcconnManager; }} Catatan: Ketika instance HTTPClient tidak lagi diperlukan dan akan di luar cakupan, penting untuk menutup manajer koneksi untuk memastikan bahwa semua koneksi yang dijaga manajer tetap tertutup dan membebaskan sumber daya sistem yang dialokasikan oleh koneksi tersebut.
Konstruktor kelas PoolingHttpClientConnectionManager di atas adalah sebagai berikut:
poolingHttpClientConnectionManager (timetolive panjang terakhir, final timeunit tunit) {this (getDefaultregistry (), null, null, null, timetolive, tunit); } Private Static Registry <ConnectionCocketFactory> getDefaultregistry () {return RegistryBuilder. <snectionCocketFactory> create () .register ("http", PlainConnectionCocketFactory.getSocketFactory () .register ("https", sslconcory (sslconcory ("https", sslconcory ("https", sslconcory. .membangun(); } Ada dua koneksi maksimum dalam konfigurasi PoolingHttpClientConnectionManager, yang mengontrol total nomor koneksi maksimum dan nomor koneksi maksimum per rute masing -masing. Jika tidak ada pengaturan eksplisit, secara default, hanya hingga 2 koneksi per rute yang diizinkan, dan jumlah total koneksi tidak melebihi 20. Nilai ini tidak cukup untuk banyak aplikasi dengan konkurensi tinggi. Nilai yang sesuai harus ditetapkan sesuai dengan situasi aktual. Idenya mirip dengan ukuran kumpulan utas. Jika semua permintaan koneksi ke URL yang sama, nilai maxperroute dapat diatur agar konsisten dengan maxtotal, sehingga koneksi dapat digunakan kembali secara lebih efisien
Catatan Khusus: Jika Anda ingin menggunakan kembali koneksi, Anda harus membuat sumber daya sistem yang ditempati dengan benar. Metode rilis adalah sebagai berikut:
Jika Anda menggunakan OutputStream, Anda harus memastikan bahwa seluruh entitas ditulis. Jika ini adalah inputstream, Anda harus ingat untuk memanggil inputStream.close () di akhir. Atau gunakan Entityutils.consume (entitas) atau entitas. Ada metode tostring di entitas, yang juga sangat nyaman (inputstream akan ditutup secara otomatis pada akhirnya ketika memanggil metode ini, tetapi dalam proses pengujian yang sebenarnya, koneksi tidak akan dilepaskan), tetapi hanya dapat digunakan jika dapat ditentukan bahwa entitas yang diterima tidak terlalu besar. Jika seluruh entitas tidak sepenuhnya dikonsumsi, koneksi tidak dapat digunakan kembali, dan segera batas waktu koneksi atau blok yang tersedia di sini tidak akan diperoleh di kumpulan koneksi (karena keadaan koneksi akan selalu terhindar, yaitu, keadaan digunakan). Karena itu, jika Anda ingin menggunakan kembali koneksi, Anda harus ingat untuk mengkonsumsi entitas sepenuhnya. Selama EOF aliran terdeteksi, metode ReleasEconnection dari pemegang koneksi akan secara otomatis dipanggil untuk diproses.
3. Koneksi Keep Alive Strategy
Spesifikasi HTTP tidak menentukan berapa lama koneksi yang persisten dapat dan harus tetap hidup. Beberapa server HTTP menggunakan header Keep-Alive non-standar untuk berkomunikasi dengan klien periode dalam hitungan detik ketika mereka bermaksud untuk menjaga koneksi di sisi server. HTTPClient dapat menggunakan informasi ini. Jika header Keep-Alive tidak ada dalam respons, HTTPClient mengasumsikan bahwa koneksi dapat tetap aktif tanpa batas waktu. Namun, banyak server HTTP yang umumnya digunakan dikonfigurasi untuk menghapus koneksi persisten setelah periode status tidak aktif untuk menghemat sumber daya sistem tanpa memberi tahu klien. Jika kebijakan default terlalu optimis, Anda mungkin perlu memberikan kebijakan kustom-jaga kustom, kodenya adalah sebagai berikut:
impor org.apache.http.headerelement; impor org.apache.http.headerelementiterator; impor org.apache.http.httpresponse; impor org.apache.http.conn.connectionkeepaLivestrategy; impor org.apache.http.message.basicheaderelementiterator; impor org.apache.http.protocol.http; impor org.apache.http.protocol.httpcontext; impor org.springframework.beans.factory.annotation.value; impor org.springframework.context.annotation.bean; impor org.springframework.context.annotation.configuration; / *** Deskripsi: Kebijakan Keeping Koneksi* @Author chhliu*/ @konfigurasi kelas publik MyConnectionKeepAliveStrate {@Value ("$ {httpclient.config.keepalivetime}") private int keepalivetime = 30; @Bean("connectionKeepAliveStrategy") public ConnectionKeepAliveStrategy connectionKeepAliveStrategy() { return new ConnectionKeepAliveStrategy() { public long getKeepAliveDuration(HttpResponse response, HttpContext context) { // Honor 'keep-alive' header HeaderElementIterator it = new BasicHeaderElementIterator( response.headeriterator (http.conn_keep_alive)); while (it.hasnext ()) {headereLement he = it.nextElement (); String param = he.getName (); Nilai string = he.getValue (); if (value! = null && param.equalSignorecase ("timeout")) {coba {return long.parselong (value) * 1000; } catch (NumberFormateSception abaikan) {}}} return 30 * 1000; }}; }} Catatan: Koneksi panjang tidak digunakan dalam semua situasi, terutama saat ini, sebagian besar sistem digunakan pada beberapa server dan memiliki fungsi penyeimbangan beban. Jika kita menjaga koneksi yang panjang saat mengakses, setelah server itu ditangguhkan, itu akan mempengaruhi klien. Pada saat yang sama, kami tidak dapat sepenuhnya menggunakan karakteristik penyeimbangan beban server. Sebaliknya, koneksi pendek lebih bermanfaat. Ini perlu ditentukan sesuai dengan kebutuhan spesifik, daripada merangkumnya dalam satu kalimat.
4. Konfigurasi Proxy HTTPClient (Konfigurasi Proxy)
Digunakan untuk mengonfigurasi proxy, kode ini sebagai berikut:
impor org.apache.http.httphost; impor org.apache.http.impl.conn.defaultProxyrouteplanner; impor org.springframework.beans.factory.annotation.value; impor org.springframework.context.annotation.bean; impor org.springframework.context.annotation.configuration; / *** Deskripsi: Proxy httpClient* @author chhliu*/ @configuration kelas publik myDefaultProxyRoutEplanner {// alamat host proxy @value ("$ {httpclient.config.proxyhost}") Private string proxyhost; // nomor port proxy @Value ("$ {httpclient.config.proxyport}") proxyport private = 8080; @Bean DefaultProxyroutePlanner DefaultProxyroutePlanner () {httphost proxy = httphost baru (this.proxyhost, this.proxyport); Return New DefaultProxyroutePlanner (proxy); }} HTTPClient tidak hanya mendukung koneksi langsung sederhana, kebijakan perutean yang kompleks dan proksi. HTTPROUTEPLANNER didasarkan pada konteks HTTP, kebijakan komputasi routing klien-ke-server. Secara umum, jika tidak ada proxy, Anda tidak perlu mengatur hal ini. Ada konsep yang sangat kritis di sini - rute: di httpclient, rute mengacu pada garis mesin lingkungan yang berjalan-> host mesin target, yaitu, jika host URL target sama, maka rute mereka sama.
5. RequestConfig
Berbagai konfigurasi yang digunakan untuk mengatur permintaan, kodenya adalah sebagai berikut:
impor org.apache.http.client.config.requestconfig; impor org.springframework.beans.factory.annotation.value; impor org.springframework.context.annotation.bean; impor org.springframework.context.annotation.configuration; @Configuration Public Class myRequestConfig {@Value ("$ {httpclient.config.connecttimeout}") private int connecttimeout = 2000; @Value ("$ {httpclient.config.connectequesttimeout}") private int connectrequestTimeOut = 2000; @Value ("$ {httpclient.config.socketTimeout}") private int socketTimeout = 2000; @Bean public revandedConfig config () {return requestConfig.custom () .setConnectionRequestTimeOut (this.connectrequestTimeOut) .setConnecttimeout (this.connecttimeout) .setsocketTimeout (this.socketTimeout) .build (); }} RequestConfig adalah beberapa konfigurasi permintaan. Ada tiga waktu batas waktu yang lebih penting. Secara default, ketiga waktu batas waktu adalah 0 (jika konfigurasi permintaan tidak diatur, parameter default akan diatur dalam getRequestConfig dari httpClientParamConfig selama eksekusi). Ini berarti menunggu tak terbatas, yang dapat dengan mudah menyebabkan semua permintaan memblokir dan menunggu tanpa batas waktu di tempat ini. Tiga timeout ini adalah:
A. ConnectionRequestTimeOut - Waktu untuk mendapatkan koneksi dari kumpulan koneksi
Waktu ini menentukan waktu batas waktu untuk mengambil koneksi dari kumpulan koneksi yang dikelola oleh ConnectionManager. Jika tidak ada koneksi yang tersedia di kumpulan koneksi, permintaan akan diblokir, dan waktu maksimum untuk menunggu ConnectionRequestTimeout. Jika belum dilayani, pengecualian ConnectionPoolTimeOutException dilemparkan dan tidak ada penantian lebih lanjut yang diizinkan.
B. ConnectTimeOut - Waktu batas waktu koneksi
Kali ini menentukan batas waktu untuk membuat koneksi dengan server melalui jaringan, yaitu, waktu tunggu koneksi untuk terhubung ke URL target setelah mendapatkan koneksi di kumpulan koneksi. Sebuah batas waktu terjadi, pengecualian ConnectionTimeOutException akan dilemparkan.
C. SocketTimeout - Perlu waktu batas waktu
Kali ini menentukan waktu batas waktu untuk data pembacaan soket, yaitu, waktu yang dibutuhkan untuk menunggu setelah menghubungkan ke server untuk mendapatkan data respons dari server, atau waktu yang diperlukan untuk mendapatkan respons setelah menghubungkan ke URL sebelumnya. Sebuah batas waktu terjadi dan pengecualian Exception SocketTimeOutsception akan dilemparkan.
6. Instantiate httpClient
HTTPClient dipakai dengan mengimplementasikan FactoryBean, kodenya adalah sebagai berikut:
impor org.apache.http.client.httpRequestRetryHandler; impor org.apache.http.client.config.requestconfig; impor org.apache.http.impl.conn.connectionkeepalivestrategy; impor org.apache.http.impl.client.closeableHttpClient; impor org.apache.http.impl.client.httpClients; impor org.apache.http.impl.conn.defaultProxyrouteplanner; impor org.apache.http.impl.conn.poolinghttpClientConnectionManager; impor org.springframework.beans.factory.disposableBean; impor org.springframework.beans.factory.factorybean; impor org.springframework.beans.factory.initializeBean; impor org.springframework.beans.factory.annotation.Autowired; impor org.springframework.stereotype.service; / *** Deskripsi: Enkapsulasi klien httpClient*/ @service ("httpclientManagerFactoryBen") kelas publik httpclientManagerFactoryBen mengimplementasikan factorybean <lenceableHttpclient>, initializeBean, DisposableBean {** objek target yang dihasilkan oleh factory; @Autowired Private ConnectionKealivestrate ConnectionkeepaliveStrategy; @Autowired private httpRequestRetryHandler httpRequestRetryHandler; @Autowired Private DefaultProxyrouteplanner ProxyroutePlanner; @Autowired Private PoolingHTTPClientConnectionManager PoolTtpcconnManager; @Autowired private requestConfig config; // Saat menghancurkan konteksnya, menghancurkan instance httpClient @Override public void destroy () melempar Exception { / * * Memanggil httpclient.close () pertama -tama akan menutup manajer koneksi, dan kemudian melepaskan semua sumber daya yang ditempati oleh httpClient, * tutup semua koneksi yang digunakan atau idle, termasuk soket yang mendasar. Karena manajer koneksi yang digunakannya ditutup di sini, * jadi ketika Anda harus membuat permintaan HTTP lain kali, Anda harus memperbarui manajer koneksi untuk membangun httpclient, * yaitu, ketika Anda perlu menutup dan membuat klien baru, manajer koneksi tidak dapat menjadi singleton. */ if (null! = this.client) {this.client.close (); }} @Override // Inisialisasi instance public void afterpropertiesset () melempar Exception {/ * * disarankan untuk menggunakan httpclients.custom untuk membuat httpClientBuilder di sini, alih -alih menggunakan httpclientBuilder.create () untuk membuat httpClientBUIMPLIENDER * Documation, HTTPCLIEDDER, HTTPCLIENDER, HTTPCLIENDER * non-utas-aman, tetapi httpClients memang tidak bisa ditiam. Objek yang tidak dapat diubah tidak hanya dapat memastikan bahwa keadaan objek tidak diubah, * tetapi juga dapat dibagikan oleh utas lain tanpa menggunakan mekanisme kunci */ this.client = httpclients.custom (). SetConnectionManager (poolhtpcconnManager) .setRetRandler (httprequeStretRetRetRyler). .setrouteplanner (proxyrouteplanner) .setDefaultrequestConfig (config) .build (); } // Kembalikan jenis instance @Override public closeableHttpClient getObject () melempar Exception {return this.client; } @Override Public Class <?> GetObjectType () {return (this.client == null? CloseableHttpclient.class: this.client.getClass ()); } // Instance yang dibangun adalah singleton@override public boolean issingleton () {return true; }}7. Tambahkan file konfigurasi
# Proxy's Host httpclient.config.proxyhost = xxx.xx.xx.xx # port proxy httpclient.config.proxyport = 8080 # Koneksi batas waktu atau pengecualian ulang tahun httpclient.config.retrytime = 3 # Koneksi waktu yang panjang, unit waktu henti httpclient.config.config. Koneksi di kumpulan koneksi httpclient.config.connmaxtotal = 20 httpclient.config.maxperroute = 20 # Koneksi batas waktu, unit ms httpclient.config.connecttimeout = 20 # Timeout, unit adalah ms httpclient.config.connecttimeout = 20 httpclient.config.connectrequestTimeOut = 2000 # sock timeout httpclient.config.socketTimeout = 2000 # Koneksi waktu bertahan hidup, unit s httpclient.config.timetolive = 60
8. Tes
Kode tes adalah sebagai berikut:
impor java.io.ioException; impor java.util.concurrent.executorservice; impor java.util.concurrent.Executors; impor javax.annotation.Resource; impor org.apache.http.consts; impor org.apache.http.parseexception; impor org.apache.http.client.clientprotocolexception; impor org.apache.http.client.methods.closeableHttpresponse; impor org.apache.http.client.methods.httpget; impor org.apache.http.impl.client.closeableHttpClient; impor org.apache.http.util.entityutils; impor org.junit.test; impor org.junit.runner.runwith; impor org.springframework.boot.test.context.springboottest; impor org.springframework.test.context.junit4.springrunner; @Runwith (springrunner.class) @springboottest kelas publik httpClientManagerFactoryBentest {// menyuntikkan instance httpClient @Resource (name = "httpClientManagerFactoryBen") klien tertutup pribadi; @Test public void test () melempar ClientProtocolException, IoException, InterruptedException {ExecutorService Service = Executors.newfixedThreadPool (2); untuk (int i = 0; i <10; i ++) {service.submit (runnable baru () {@Override public void run () {System.out.println ("Thread saat ini adalah:"+thread.currentThread (). getName ()); httpentity Entity = null; try {ht). Httpget ("https: // localhost: 8080/testjson"); System.out.println ("========================================================================================================================================================================================= Connection} ClientProtocoleException e) {E.PrintStackTrace (); }});} Thread.sleep (60000); Melalui langkah -langkah di atas, enkapsulasi httpClient pada dasarnya selesai. Jika Anda perlu lebih rinci, Anda dapat secara bertahap meningkatkan httpClient sebagai httpClientTemplate sesuai dengan ide -ide di atas, karena closeableHttpClient menggunakan mekanisme panggilan balik secara internal, yang mirip dengan starter jdbctemplate atau redistemplate hingga layanan dapat disediakan dalam bentuk starter boot musim semi.
Di atas adalah semua konten artikel ini. Saya berharap ini akan membantu untuk pembelajaran semua orang dan saya harap semua orang akan lebih mendukung wulin.com.