续(四)
2.3.2. HTTP请求执行器
HttpRequestExecutor是一个基于阻塞I/O模型的客户端HTTP协议处理者它为客户端消息处理实现了HTTP协议的基本需求,就像RFC2616描述地那样。HttpRequestExecutor依赖HttpProcessor实例为所有的离埠消息和到埠消息产生必要性协议头,还有应用通用的、交叉消息转换到所有的到埠和离埠消息。一旦请求易经被执行和响应已经被接收,应用程序特殊的处理就能在HttpRequestExecutor外部实现。
*************************************************************************
* *
* HttpClientConnection conn = <...> *
* *
* HttpProcessor httpproc = HttpProcessorBuilder.create() *
* .add(new RequestContent()) *
* .add(new RequestTargetHost()) *
* .add(new RequestConnControl()) *
* .add(new RequestUserAgent("MyClient/1.1")) *
* .add(new RequestExpectContinue(true)) *
* .build(); *
* HttpRequestExecutor httpexecutor = new HttpRequestExecutor(); *
* *
* HttpRequest request = new BasicHttpRequest("GET", "/"); *
* HttpCoreContext context = HttpCoreContext.create(); *
* httpexecutor.preProcess(request, httpproc, context); *
* HttpResponse response = httpexecutor.execute(request, conn, context); *
* httpexecutor.postProcess(response, httpproc, context); *
* *
* HttpEntity entity = response.getEntity(); *
* EntityUtils.consume(entity); *
* *
*************************************************************************
HttpRequestExecutor的方法在多线程中执行是安全的。这允许在多个连接上同时执行请求,只要所有使用协议拦截器的HttpRequestExecutor是线程安全的即可。
2.3.3. 连接持久化/复用
ConnectionReuseStrategy接口被期望在当前消息传输已经被完成之后去决定底层连接是否被重新用于更多的消息处理。默认的连接重用策略尝试在无论何时都保持连接的活性。首先,它会检查用于传送消息的HTTP协议版本号。HTTP/1.1连接默认是持久化的,而当不是HTTP/1.0时。第二,它会检查Connection头的值。同等端可以通过在Connection头中发送Keep-Alive或Close值来指示是否打算在对端重用连接。第三,基于附加实体的属性,如果可用的话,决定是否安全地重用连接。
2.4. 连接池
有效的客户端HTTP传输尝尝需要有效地重用持久化连接。HttpCore通过提供对持久化HTTP连接的池化管理的支持来促进连接重用的过程。连接池实现是线程安全的和能够被多个消费者并发使用。
默认时池子只允许总共20个并发连接和每个唯一路径2个并发连接。这个2个连接的限制是由于HTTP规范所规定的。然而,这在实际中往往限制太过了。一个能在运行时改变池子配置允许更多的并发连接则依赖一个特定的应用程序上下文。
*****************************************************************
* *
* HttpHost target = new HttpHost("localhost"); *
* BasicConnPool connpool = new BasicConnPool(); *
* connpool.setMaxTotal(200); *
* connpool.setDefaultMaxPerRoute(10); *
* connpool.setMaxPerRoute(target, 20); *
* Future future = connpool.lease(target, null); *
* BasicPoolEntry poolEntry = future.get(); *
* HttpClientConnection conn = poolEntry.getConnection(); *
* *
*****************************************************************
请注意连接池没办法知道被租用的连接是否仍旧在被使用。去确认连接一旦不再被需要而被释放回池子,这个是连接池使用者的责任,即使连接不可用。
*****************************************************************
* *
* BasicConnPool connpool = <...> *
* Future future = connpool.lease(target, null); *
* BasicPoolEntry poolEntry = future.get(); *
* try { *
* HttpClientConnection conn = poolEntry.getConnection(); *
* } finally { *
* connpool.release(poolEntry, true); *
* } *
* *
*****************************************************************
连接池的状态能够在运行时被询问。
**************************************************************************
* *
* HttpHost target = new HttpHost("localhost"); *
* BasicConnPool connpool = <...> *
* PoolStats totalStats = connpool.getTotalStats(); *
* System.out.println("total available: " + totalStats.getAvailable()); *
* System.out.println("total leased: " + totalStats.getLeased()); *
* System.out.println("total pending: " + totalStats.getPending()); *
* PoolStats targetStats = connpool.getStats(target); *
* System.out.println("target available: " + targetStats.getAvailable()); *
* System.out.println("target leased: " + targetStats.getLeased()); *
* System.out.println("target pending: " + targetStats.getPending()); *
* *
**************************************************************************
请注意连接池不会主动驱逐失效的连接。即使失效的连接不会被租用给请求者,池子也可能积累陈旧的连接特别是在休止期之后。在较大的休止期后从池子中强制驱逐失效的和空闲的连接这通常是明智的。
********************************************
* *
* BasicConnPool connpool = <...> *
* connpool.closeExpired(); *
* connpool.closeIdle(1, TimeUnit.MINUTES); *
* *
********************************************
跟踪从池子中租赁来的连接和确保一旦它们不再被需要或被主动用就立刻被释放这通常被认为是消费方的职责。然而,BasicConnPool提供了protected类型的方法去枚举可用的空闲连接和当前那些从池子中租赁来的连接。参照特定的规范下这使得池子消费者可以查询连接状态和有选择地终结连接。
**********************************************************************************************************
* *
* static class MyBasicConnPool extends BasicConnPool { *
* *
* @Override *
* protected void enumAvailable(final PoolEntryCallback callback) { *
* super.enumAvailable(callback); *
* } *
* *
* @Override *
* protected void enumLeased(final PoolEntryCallback callback) { *
* super.enumLeased(callback); *
* } *
* } *
* *
**********************************************************************************************************
************************************************************************************
* *
* MyBasicConnPool connpool = new MyBasicConnPool(); *
* connpool.enumAvailable(new PoolEntryCallback() { *
* *
* @Override *
* public void process(final PoolEntry entry) { *
* Date creationTime = new Date(entry.getCreated()); *
* if (creationTime.before(someTime)) { *
* entry.close(); *
* } *
* } *
* *
* }); *
* *
************************************************************************************
2.5. TLS/SSL支持
阻塞连接能够被绑定到任何任意的套接字上。这使得SSL的支持变得直截了当。为了使所有传输的消息的安全性超过被TLS/SSL保护的连接,任何SSLSocket实例都能够被绑定到一个阻塞连接上。
***********************************************************************************
* *
* SSLContext sslcontext = SSLContexts.createSystemDefault(); *
* SocketFactory sf = sslcontext.getSocketFactory(); *
* SSLSocket socket = (SSLSocket) sf.createSocket("somehost", 443); *
* // Enforce TLS and disable SSL *
* socket.setEnabledProtocols(new String[] { *
* "TLSv1", *
* "TLSv1.1", *
* "TLSv1.2" }); *
* // Enforce strong ciphers *
* socket.setEnabledCipherSuites(new String[] { *
* "TLS_RSA_WITH_AES_256_CBC_SHA", *
* "TLS_DHE_RSA_WITH_AES_256_CBC_SHA", *
* "TLS_DHE_DSS_WITH_AES_256_CBC_SHA" }); *
* DefaultBHttpClientConnection conn = new DefaultBHttpClientConnection(8 * 1204); *
* conn.bind(socket); *
* *
***********************************************************************************
2.6. 嵌入式HTTP服务器
如下描述,自4.4版本起HttpCore附加了一个基于阻塞I/O组件的嵌入式HTTP服务器。
**************************************************************
* *
* HttpRequestHandler requestHandler = <...> *
* HttpProcessor httpProcessor = <...> *
* SocketConfig socketConfig = SocketConfig.custom() *
* .setSoTimeout(15000) *
* .setTcpNoDelay(true) *
* .build(); *
* final HttpServer server = ServerBootstrap.bootstrap() *
* .setListenerPort(8080) *
* .setHttpProcessor(httpProcessor) *
* .setSocketConfig(socketConfig) *
* .setExceptionLogger(new StdErrorExceptionLogger()) *
* .registerHandler("*", requestHandler) *
* .create(); *
* server.start(); *
* server.awaitTermination(Long.MAX_VALUE, TimeUnit.DAYS); *
* Runtime.getRuntime().addShutdownHook(new Thread() { *
* @Override *
* public void run() { *
* server.shutdown(5, TimeUnit.SECONDS); *
* } }); *
* *
**************************************************************
未完待续。。。
阅读(2943) | 评论(0) | 转发(0) |