这里简单地记录了 org.apache.commons.httpclient 与 org.apache.commons.httpclient.MultiThreadedHttpConnectionManager 相结合,构建 http 连接池,提高这种因多次连接而产生不必要的时间消耗效率. 这里还有个很重要的类,org.apache.commons.httpclient.methods.PostMethod,它是整个http请求的业务处理类;
org.apache.commons.httpclient.MultiThreadedHttpConnectionManager: 负责连接的管理; 基于服务器ip为key; 存在两个池,一个用于存放 服务器集合,另一个用于存放各服务器所对应的 连接集合
org.apache.commons.httpclient.methods.PostMethod: 负责http业务调度; 1:进行请求头的拼装 2:调用connection连接,进行数据的请求 3:响应的处理,解析相应的请求头信息
org.apache.commons.httpclient : 封装类,把上述的 MultiThreadedHttpConnectionManager 与 PostMethod 整合,供外部使用.
http仅仅只是一个超文本协议,非传输技术,作用于应用层; 它依赖于传输层的 tcp/ip 协议,进行两端的信息交互; 而tcp/ip 也只是一种交互协议,而socket是目前较为流行的开源java方法类. 因此客户端与服务端间进行http协议交互,实际上是通过下层的socket工具类,进行 tcp/ip 交互.
这里也顺便提一下平常用开的jdbc,它是直接走 传输层,利用 tcp/ip 协议与数据库进行交互,实际上还是通过socket技术与数据库进行二进制的协议数据交互.(有空可以百度了解 二进制协议数据结构)
首先开始我们以 HttpClientUtil 测试类进行开篇,简单地使用 HttpClient 与server进行数据请求.
import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.net.SocketTimeoutException; import java.net.UnknownHostException; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import org.apache.commons.httpclient.DefaultHttpMethodRetryHandler; import org.apache.commons.httpclient.Header; import org.apache.commons.httpclient.HttpClient; import org.apache.commons.httpclient.HttpConnectionManager; import org.apache.commons.httpclient.HttpException; import org.apache.commons.httpclient.MultiThreadedHttpConnectionManager; import org.apache.commons.httpclient.NameValuePair; import org.apache.commons.httpclient.methods.PostMethod; import org.apache.commons.httpclient.params.HttpConnectionManagerParams; import org.apache.commons.httpclient.params.HttpMethodParams; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.log4j.chainsaw.Main; import com.g3net.tool.HttpUtils; public class HttpClientUtil { /** * 日志处理类 */ private static final Log log = LogFactory.getLog(HttpClientUtil.class); // 读取超时 private final static int SOCKET_TIMEOUT = 10000; // 连接超时 private final static int CONNECTION_TIMEOUT = 10000; // 每个HOST的最大连接数量 private final static int MAX_CONN_PRE_HOST = 20; // 连接池的最大连接数 private final static int MAX_CONN = 60; // 连接池 private final static HttpConnectionManager httpConnectionManager; static { httpConnectionManager = new MultiThreadedHttpConnectionManager(); HttpConnectionManagerParams params = httpConnectionManager.getParams(); params.setConnectionTimeout(CONNECTION_TIMEOUT); params.setSoTimeout(SOCKET_TIMEOUT); params.setDefaultMaxConnectionsPerHost(MAX_CONN_PRE_HOST); params.setMaxTotalConnections(MAX_CONN); } /** * 发送主要方法,异常捕获 * @param post * @param code * @return */ public static String doHttpRequest(PostMethod post, String code) { HttpClient httpClient = new HttpClient(httpConnectionManager); BufferedReader in = null; String resultString = ""; try { httpClient.executeMethod(post); in = new BufferedReader(new InputStreamReader(post .getResponseBodyAsStream(), code)); StringBuffer buffer = new StringBuffer(); String line = ""; while ((line = in.readLine()) != null) { buffer.append(line); } resultString = buffer.toString(); } catch (SocketTimeoutException e) { log.error("连接超时" + e.toString()); resultString = returnError("连接超时"); } catch (HttpException e) { log.error("读取外部服务器数据失败" + e.toString()); resultString = returnError("读取外部服务器数据失败"); } catch (UnknownHostException e) { log.error("请求的主机地址无效" + e.toString()); resultString = returnError("请求的主机地址无效"); } catch (IOException e) { log.error("向外部接口发送数据失败" + e.toString()); resultString = returnError("向外部接口发送数据失败"); } finally { if (in != null) { try { in.close(); } catch (IOException e) { e.printStackTrace(); } } post.releaseConnection(); } return resultString; } /** * 设置一下返回错误的通用提示,可以自定义格式. * @param reason * @return */ public static String returnError(String reason) { StringBuffer buffer = new StringBuffer(); buffer.append("<?xml version=\"1.0\" encoding=\"GBK\"?>"); buffer.append("<Response>"); buffer.append("<Success>false</Success>"); buffer.append("<reason>"); buffer.append(reason); buffer.append("</reason>"); buffer.append("</Response>"); return buffer.toString(); } public final static String REQUEST_HEADER = "x-forwarded-for"; /** * 将客户IP写入请求头 * 这个设置可以伪装IP请求,注意使用 * @param client * @param ip * @return */ public static void resetRequestHeader(HttpClient client, String ip) { List<Header> headers = new ArrayList<Header>(); headers.add(new Header(REQUEST_HEADER, ip)); client.getHostConfiguration().getParams().setParameter( "http.default-headers", headers); } public static void main(String[] args) throws Exception{ String url = "http://192.168.162.38/applib/webcontent/interface/searchnew.jsp?key=theme&ty=0&n=100"; PostMethod postMethod = new PostMethod(url);// 放地址 //请求头设置 postMethod.setRequestHeader("Host", "www.baidu.com"); postMethod.setRequestHeader("Connection", "keep-alive"); postMethod.setRequestHeader("User-Agent", "Mozilla/5.0 (X11; Linux i686) AppleWebKit/537.4 (KHTML, like Gecko) Chrome/22.0.1229.92 Safari/537.4"); postMethod.setRequestHeader("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"); postMethod.setRequestHeader("Accept-Encoding", "gzip,deflate,sdch"); postMethod.setRequestHeader("Accept-Language", "zh-CN,zh;q=0.8"); postMethod.setRequestHeader("Accept-Charset", "GBK,utf-8;q=0.7,*;q=0.3"); String result = HttpClientUtil.doHttpRequest(postMethod, "utf-8"); System.out.println(result); } }
httpClient.executeMethod(post); public int executeMethod(HttpMethod method) throws IOException, HttpException { LOG.trace("enter HttpClient.executeMethod(HttpMethod)"); return executeMethod(null, method, null); }
在HttpClient 中,我们发现,它把 连接池以及服务的请求处理,封装到了 org.apache.commons.httpclient.HttpMethodDirector.
public int executeMethod(HostConfiguration hostconfig, HttpMethod method, HttpState state) throws IOException, HttpException { LOG.trace("enter HttpClient.executeMethod(HostConfiguration,HttpMethod,HttpState)"); if(method == null) throw new IllegalArgumentException("HttpMethod parameter may not be null"); //这里是获取服务端信息,ip 端口号 协议 等. HostConfiguration defaulthostconfig = getHostConfiguration(); if(hostconfig == null) hostconfig = defaulthostconfig; URI uri = method.getURI(); if(hostconfig == defaulthostconfig || uri.isAbsoluteURI()) { hostconfig = (HostConfiguration)hostconfig.clone(); if(uri.isAbsoluteURI()) hostconfig.setHost(uri); } //这里把连接的获取,以及服务的请求,给封装到一齐 HttpMethodDirector methodDirector = new HttpMethodDirector(getHttpConnectionManager(), hostconfig, params, state != null ? state : getState()); methodDirector.executeMethod(method); return method.getStatusCode(); }
在 org.apache.commons.httpclient.HttpMethodDirector ,通过 executeMethod 进行业务请求处理
public void executeMethod(HttpMethod method) throws IOException, HttpException { if(method == null) throw new IllegalArgumentException("Method may not be null"); hostConfiguration.getParams().setDefaults(params); method.getParams().setDefaults(hostConfiguration.getParams()); Collection defaults = (Collection)hostConfiguration.getParams().getParameter("http.default-headers"); if(defaults != null) { for(Iterator i = defaults.iterator(); i.hasNext(); method.addRequestHeader((Header)i.next())); } int maxRedirects = params.getIntParameter("http.protocol.max-redirects", 100); int redirectCount = 0; do { if(conn != null && !hostConfiguration.hostEquals(conn)) { conn.setLocked(false); conn.releaseConnection(); conn = null; } if(conn == null) { //通过连接池connectionManager,从池中提取有效连接 conn = connectionManager.getConnectionWithTimeout(hostConfiguration, params.getConnectionManagerTimeout()); conn.setLocked(true); if(params.isAuthenticationPreemptive() || state.isAuthenticationPreemptive()) { LOG.debug("Preemptively sending default basic credentials"); method.getHostAuthState().setPreemptive(); method.getHostAuthState().setAuthAttempted(true); if(conn.isProxied() && !conn.isSecure()) { method.getProxyAuthState().setPreemptive(); method.getProxyAuthState().setAuthAttempted(true); } } } authenticate(method); executeWithRetry(method); if(connectMethod != null) { fakeResponse(method); break; } boolean retry = false; if(isRedirectNeeded(method) && processRedirectResponse(method)) { retry = true; if(++redirectCount >= maxRedirects) { LOG.error("Narrowly avoided an infinite loop in execute"); throw new RedirectException("Maximum redirects (" + maxRedirects + ") exceeded"); } if(LOG.isDebugEnabled()) LOG.debug("Execute redirect " + redirectCount + " of " + maxRedirects); } if(isAuthenticationNeeded(method) && processAuthenticationResponse(method)) { LOG.debug("Retry authentication"); retry = true; } if(!retry) break; if(method.getResponseBodyAsStream() != null) method.getResponseBodyAsStream().close(); } while(true); if(conn != null) conn.setLocked(false); if((releaseConnection || method.getResponseBodyAsStream() == null) && conn != null) conn.releaseConnection(); break MISSING_BLOCK_LABEL_583; Exception exception; exception; if(conn != null) conn.setLocked(false); if((releaseConnection || method.getResponseBodyAsStream() == null) && conn != null) conn.releaseConnection(); throw exception; }
private void executeWithRetry(HttpMethod method) throws IOException, HttpException { int execCount = 0; _L2: execCount++; if(LOG.isTraceEnabled()) LOG.trace("Attempt number " + execCount + " to process request"); if(conn.getParams().isStaleCheckingEnabled()) conn.closeIfStale(); if(!conn.isOpen()) { conn.open(); if(conn.isProxied() && conn.isSecure() && !(method instanceof ConnectMethod) && !executeConnect()) return; } try { try { applyConnectionParams(method); //method 为业务处理类,包含了请求头/响应头等信息,但需要 conn 作为桥梁与服务器进行通讯 method.execute(state, conn); break MISSING_BLOCK_LABEL_452; } catch(HttpException e) { throw e; } catch(IOException e) { LOG.debug("Closing the connection."); conn.close(); HttpMethodRetryHandler handler; if(method instanceof HttpMethodBase) { handler = ((HttpMethodBase)method).getMethodRetryHandler(); if(handler != null && !handler.retryMethod(method, conn, new HttpRecoverableException(e.getMessage()), execCount, method.isRequestSent())) { LOG.debug("Method retry handler returned false. Automatic recovery will not be attempted"); throw e; } } handler = (HttpMethodRetryHandler)method.getParams().getParameter("http.method.retry-handler"); if(handler == null) handler = new DefaultHttpMethodRetryHandler(); if(!handler.retryMethod(method, e, execCount)) { LOG.debug("Method retry handler returned false. Automatic recovery will not be attempted"); throw e; } if(LOG.isInfoEnabled()) LOG.info("I/O exception (" + e.getClass().getName() + ") caught when processing request: " + e.getMessage()); if(LOG.isDebugEnabled()) LOG.debug(e.getMessage(), e); LOG.info("Retrying request"); } } catch(IOException e) { if(conn.isOpen()) { LOG.debug("Closing the connection."); conn.close(); } releaseConnection = true; throw e; } catch(RuntimeException e) { if(conn.isOpen()) { LOG.debug("Closing the connection."); conn.close(); } releaseConnection = true; throw e; } if(true) goto _L2; else goto _L1 _L1: }
上述干了许多活儿,到最后还是调用了最开始的 org.apache.commons.httpclient.methods.PostMethod 中的 excute 方法,进行http请求
public int execute(HttpState state, HttpConnection conn) throws HttpException, IOException { LOG.trace("enter HttpMethodBase.execute(HttpState, HttpConnection)"); responseConnection = conn; checkExecuteConditions(state, conn); statusLine = null; connectionCloseForced = false; conn.setLastResponseInputStream(null); if(effectiveVersion == null) effectiveVersion = params.getVersion(); //请求信息发送,包括些请求头/请求体等 writeRequest(state, conn); requestSent = true; readResponse(state, conn); used = true; return statusLine.getStatusCode(); } protected void writeRequest(HttpState state, HttpConnection conn) throws IOException, HttpException { int readTimeout; LOG.trace("enter HttpMethodBase.writeRequest(HttpState, HttpConnection)"); //以下则根据 http 超文本协议,进行协议内容发送,包括请求头/请求体 writeRequestLine(state, conn); writeRequestHeaders(state, conn); conn.writeLine(); if(Wire.HEADER_WIRE.enabled()) Wire.HEADER_WIRE.output("\r\n"); HttpVersion ver = getParams().getVersion(); Header expectheader = getRequestHeader("Expect"); String expectvalue = null; if(expectheader != null) expectvalue = expectheader.getValue(); if(expectvalue == null || expectvalue.compareToIgnoreCase("100-continue") != 0) break MISSING_BLOCK_LABEL_265; if(!ver.greaterEquals(HttpVersion.HTTP_1_1)) break MISSING_BLOCK_LABEL_247; conn.flushRequestOutputStream(); readTimeout = conn.getParams().getSoTimeout(); conn.setSocketTimeout(3000); readStatusLine(state, conn); processStatusLine(state, conn); readResponseHeaders(state, conn); processResponseHeaders(state, conn); if(statusLine.getStatusCode() == 100) { statusLine = null; LOG.debug("OK to continue received"); break MISSING_BLOCK_LABEL_184; } conn.setSocketTimeout(readTimeout); return; conn.setSocketTimeout(readTimeout); break MISSING_BLOCK_LABEL_265; InterruptedIOException e; e; if(!ExceptionUtil.isSocketTimeoutException(e)) throw e; removeRequestHeader("Expect"); LOG.info("100 (continue) read timeout. Resume sending the request"); conn.setSocketTimeout(readTimeout); break MISSING_BLOCK_LABEL_265; Exception exception; exception; conn.setSocketTimeout(readTimeout); throw exception; removeRequestHeader("Expect"); LOG.info("'Expect: 100-continue' handshake is only supported by HTTP/1.1 or higher"); writeRequestBody(state, conn); conn.flushRequestOutputStream(); return; } protected void readResponse(HttpState state, HttpConnection conn) throws IOException, HttpException { LOG.trace("enter HttpMethodBase.readResponse(HttpState, HttpConnection)"); do { if(statusLine != null) break; //读取服务器返回内容,主要为 http 响应信息 readStatusLine(state, conn); processStatusLine(state, conn); readResponseHeaders(state, conn); processResponseHeaders(state, conn); int status = statusLine.getStatusCode(); if(status >= 100 && status < 200) { if(LOG.isInfoEnabled()) LOG.info("Discarding unexpected response: " + statusLine.toString()); statusLine = null; } } while(true); readResponseBody(state, conn); processResponseBody(state, conn); }
来到这里,我们再回过头来看看,在 org.apache.commons.httpclient.HttpMethodDirector 处理过程中,是如何获取到与服务器间的连接,见org.apache.commons.httpclient.MultiThreadedHttpConnectionManager
public HttpConnection getConnectionWithTimeout(HostConfiguration hostConfiguration, long timeout) throws ConnectionPoolTimeoutException { LOG.trace("enter HttpConnectionManager.getConnectionWithTimeout(HostConfiguration, long)"); if(hostConfiguration == null) throw new IllegalArgumentException("hostConfiguration is null"); if(LOG.isDebugEnabled()) LOG.debug("HttpConnectionManager.getConnection: config = " + hostConfiguration + ", timeout = " + timeout); HttpConnection conn = doGetConnection(hostConfiguration, timeout); return new HttpConnectionAdapter(conn); }
private HttpConnection doGetConnection(HostConfiguration hostConfiguration, long timeout) throws ConnectionPoolTimeoutException { HttpConnection connection; int maxHostConnections; connection = null; maxHostConnections = params.getMaxConnectionsPerHost(hostConfiguration); int maxTotalConnections = params.getMaxTotalConnections(); ConnectionPool connectionpool = connectionPool; JVM INSTR monitorenter ; HostConnectionPool hostPool; WaitingThread waitingThread; boolean useTimeout; long timeToWait; long startWait; hostConfiguration = new HostConfiguration(hostConfiguration); //这里是根据服务端ip,从数据池 connectionPool 里面提取对应的 连接池. //因此这里涉及到两个池:一个是 connectionPool,可以存储多服务器; 另一个是 hostPool,存储了一台服务器所有的连接. hostPool = connectionPool.getHostPool(hostConfiguration, true); waitingThread = null; useTimeout = timeout > 0L; timeToWait = timeout; startWait = 0L; long endWait = 0L; _L2: if(connection != null) break; /* Loop/switch isn't completed */ if(shutdown) throw new IllegalStateException("Connection factory has been shutdown."); //下面是根据 hostPool 里面的连接数情况,进行连接的获取 if(hostPool.freeConnections.size() > 0) { connection = connectionPool.getFreeConnection(hostConfiguration); continue; /* Loop/switch isn't completed */ } if(hostPool.numConnections < maxHostConnections && connectionPool.numConnections < maxTotalConnections) { connection = connectionPool.createConnection(hostConfiguration); continue; /* Loop/switch isn't completed */ } if(hostPool.numConnections < maxHostConnections && connectionPool.freeConnections.size() > 0) { connectionPool.deleteLeastUsedConnection(); connection = connectionPool.createConnection(hostConfiguration); continue; /* Loop/switch isn't completed */ } if(useTimeout && timeToWait <= 0L) throw new ConnectionPoolTimeoutException("Timeout waiting for connection"); if(LOG.isDebugEnabled()) LOG.debug("Unable to get a connection, waiting..., hostConfig=" + hostConfiguration); if(waitingThread == null) { waitingThread = new WaitingThread(); waitingThread.hostConnectionPool = hostPool; waitingThread.thread = Thread.currentThread(); } else { waitingThread.interruptedByConnectionPool = false; } if(useTimeout) startWait = System.currentTimeMillis(); hostPool.waitingThreads.addLast(waitingThread); connectionPool.waitingThreads.addLast(waitingThread); connectionPool.wait(timeToWait); if(!waitingThread.interruptedByConnectionPool) { hostPool.waitingThreads.remove(waitingThread); connectionPool.waitingThreads.remove(waitingThread); } if(useTimeout) { long endWait = System.currentTimeMillis(); timeToWait -= endWait - startWait; } continue; /* Loop/switch isn't completed */ InterruptedException e; e; if(!waitingThread.interruptedByConnectionPool) { LOG.debug("Interrupted while waiting for connection", e); throw new IllegalThreadStateException("Interrupted while waiting in MultiThreadedHttpConnectionManager"); } if(!waitingThread.interruptedByConnectionPool) { hostPool.waitingThreads.remove(waitingThread); connectionPool.waitingThreads.remove(waitingThread); } if(useTimeout) { long endWait = System.currentTimeMillis(); timeToWait -= endWait - startWait; } if(true) goto _L2; else goto _L1 _L1: Exception exception; break MISSING_BLOCK_LABEL_555; exception; if(!waitingThread.interruptedByConnectionPool) { hostPool.waitingThreads.remove(waitingThread); connectionPool.waitingThreads.remove(waitingThread); } if(useTimeout) { long endWait = System.currentTimeMillis(); timeToWait -= endWait - startWait; } throw exception; Exception exception1; exception1; throw exception1; return connection; }
public synchronized HttpConnection createConnection(HostConfiguration hostConfiguration) { HostConnectionPool hostPool = getHostPool(hostConfiguration, true); if(MultiThreadedHttpConnectionManager.LOG.isDebugEnabled()) MultiThreadedHttpConnectionManager.LOG.debug("Allocating new connection, hostConfig=" + hostConfiguration); //创建连接,这里的继承了 httpconnection ,根据 ip port 信息,与服务器建立 socket 连接 HttpConnectionWithReference connection = new HttpConnectionWithReference(hostConfiguration); connection.getParams().setDefaults(params); connection.setHttpConnectionManager(MultiThreadedHttpConnectionManager.this); numConnections++; hostPool.numConnections++; MultiThreadedHttpConnectionManager.storeReferenceToConnection(connection, hostConfiguration, this); return connection; }
public HttpConnection(String proxyHost, int proxyPort, String host, int port, Protocol protocol) { hostName = null; portNumber = -1; proxyHostName = null; proxyPortNumber = -1; socket = null; inputStream = null; outputStream = null; lastResponseInputStream = null; isOpen = false; params = new HttpConnectionParams(); locked = false; usingSecureSocket = false; tunnelEstablished = false; if(host == null) throw new IllegalArgumentException("host parameter is null"); if(protocol == null) { throw new IllegalArgumentException("protocol is null"); } else { proxyHostName = proxyHost; proxyPortNumber = proxyPort; hostName = host; portNumber = protocol.resolvePort(port); protocolInUse = protocol; return; } }
public void open() throws IOException { LOG.trace("enter HttpConnection.open()"); String host = proxyHostName != null ? proxyHostName : hostName; int port = proxyHostName != null ? proxyPortNumber : portNumber; assertNotOpen(); if(LOG.isDebugEnabled()) LOG.debug("Open connection to " + host + ":" + port); try { if(socket == null) { usingSecureSocket = isSecure() && !isProxied(); ProtocolSocketFactory socketFactory = null; if(isSecure() && isProxied()) { Protocol defaultprotocol = Protocol.getProtocol("http"); socketFactory = defaultprotocol.getSocketFactory(); } else { socketFactory = protocolInUse.getSocketFactory(); } //与服务器间建立起socket通道,进行后续的数据交互 socket = socketFactory.createSocket(host, port, localAddress, 0, params); } socket.setTcpNoDelay(params.getTcpNoDelay()); socket.setSoTimeout(params.getSoTimeout()); int linger = params.getLinger(); if(linger >= 0) socket.setSoLinger(linger > 0, linger); int sndBufSize = params.getSendBufferSize(); if(sndBufSize >= 0) socket.setSendBufferSize(sndBufSize); int rcvBufSize = params.getReceiveBufferSize(); if(rcvBufSize >= 0) socket.setReceiveBufferSize(rcvBufSize); int outbuffersize = socket.getSendBufferSize(); if(outbuffersize > 2048 || outbuffersize <= 0) outbuffersize = 2048; int inbuffersize = socket.getReceiveBufferSize(); if(inbuffersize > 2048 || inbuffersize <= 0) inbuffersize = 2048; inputStream = new BufferedInputStream(socket.getInputStream(), inbuffersize); outputStream = new BufferedOutputStream(socket.getOutputStream(), outbuffersize); isOpen = true; } catch(IOException e) { closeSocketAndStreams(); throw e; } }
相关推荐
总之,Apache HttpClient 4.5是Android开发中的重要工具,通过Eclipse查看源码能够深入理解其工作原理,提高开发效率和代码质量。在实际应用中,开发者可以根据需求选择是否使用HttpClient,并结合源码进行问题排查...
1. **源码分析**:源码是未经反编译的,这意味着我们可以直接阅读和理解开发者原始的编程思路。HttpClient的源码包含了大量类和接口,如`CloseableHttpClient`、`HttpGet`、`HttpPost`等,这些类用于构建和发送HTTP...
总而言之,通过对 Apache Camel 的 `direct`、`http`、`jdbc` 和 `mybatis` 组件的源码分析,我们可以全面掌握这些组件的内部运作机制,从而在实际项目中更加得心应手地应用它们。这是一项对于任何想要成为高级 ...
在深入理解HttpClient源码的过程中,我们可以学习到HTTP协议的实现细节,以及如何进行请求和响应的处理。 1. **HTTP协议基础** HTTP(超文本传输协议)是互联网上应用最广泛的一种网络协议,用于从万维网服务器...
通过分析这些测试用例,我们可以更深入地了解 HttpClient 的功能和限制。 总结,HttpClient 4.5 是一款强大且灵活的 HTTP 客户端库,其源码结构清晰,设计模式巧妙,通过深入学习和实践,开发者可以更好地利用它来...
HttpClient 4.5的源码分析可以帮助我们深入理解其内部工作原理,包括连接池管理、线程安全、异步操作、SSL/TLS配置、代理设置、超时控制等方面。源码中的关键类包括`CloseableHttpClient`、`HttpGet`、`HttpPost`、`...
四、源码分析 拥有源码可以深入理解其内部工作原理,例如: 1. `HttpCore`模块提供了HTTP协议的基本实现,包括连接管理、请求和响应处理等。 2. `HttpAsyncClient`模块提供了异步HTTP客户端实现,适合处理大量并发...
Apache HttpClient 是一个强大的Java库,用于执行HTTP请求。它提供了高度可配置和灵活的机制,使得开发者能够方便地实现各种HTTP协议操作。这个库广泛应用于需要与Web服务器交互的Java应用中,例如发送GET、POST请求...
对于源码分析,`httpcomponents-client-4.5.zip`包含了HttpClient 4.5的完整源代码,开发者可以通过阅读源码来更深入理解其工作原理,例如: - 如何配置和管理连接池。 - 请求和响应的生命周期以及处理流程。 - 如何...
三、源码分析 在`easy-httpclient-master`压缩包中,包含了项目的源代码,你可以深入研究`HttpClientBuilder`、`HttpInvoker`、`MapperScannerConfigurer`等关键类,了解其实现原理。例如: - `HttpClientBuilder`...
标签“源码”表明博客可能会深入到HttpClient的内部工作原理,分析其源代码,帮助开发者更好地理解和定制这个库。而“工具”标签可能意味着它还会讨论如何将HttpClient与其他工具或框架集成,例如测试框架或者构建...
在HttpClient中,它用于记录请求和响应的详细信息,帮助调试和性能分析。 2. **commons-codec**:提供了各种编码算法,如Base64、URL编码和ASCII85编码,HttpClient用它来处理请求和响应中的编码问题,特别是在处理...
关于源码分析,HttpClient的设计基于一系列接口和抽象类,使其具有高度可扩展性。例如,`CloseableHttpClient`是客户端的顶级接口,`HttpGet`和`HttpPost`代表不同的HTTP方法。内部的`HttpRequestBase`类是所有请求...
本篇文章将详细讲解如何使用HttpClient进行模拟登录操作,结合源码分析,帮助开发者深入理解其工作原理。 HttpClient库由Apache基金会开发,提供了全面的HTTP协议支持,包括标准与扩展的HTTP方法、连接管理、重试...
四、HttpClient源码分析 HttpClient的源码设计遵循了职责单一原则,每个组件都有明确的职责。例如,`HttpRequestExecutor`负责执行HTTP请求,`HttpClientConnectionManager`管理连接,`CloseableHttpClient`实现了...
6. **源码分析**:如果博客涉及源码层面,可能会讲解HttpClient的内部设计模式,如工厂方法、回调接口,以及关键类和方法的工作流程。 7. **最佳实践**:分享优化HttpClient性能的方法,如适当配置连接超时、避免...
本篇文章将深入探讨HTTPClient 4.5.5版本中的关键知识点,包括它的核心组件、使用场景、配置和源码分析。 首先,HTTPClient 4.5.5包含的核心组件主要有以下几个: 1. **HttpClient**:这是整个库的核心,它负责...
读者将学习到如何配置HttpClient实例,设置请求参数,处理响应,并通过源码分析了解其实现细节。同时,还会接触到日志管理和编码转换的相关知识,这些都是Java开发中与网络通信密切相关的技能。
总结起来,这个项目利用了Apache HTTPClient来查询股票信息,结合CSV解析库处理返回的数据,可能通过一个股票代码列表文件批量查询。这涉及到网络编程、HTTP协议、数据解析以及文件操作等多个IT领域的知识点。
四、HttpClient源码分析 下载的"HttpClientJarAndSource"资源包含了HttpClient的源代码,这对于开发者深入理解其工作原理、调试问题或进行定制化开发非常有价值。通过阅读源码,我们可以学习到网络请求的底层实现,...