- 浏览: 1841551 次
- 性别:
- 来自: 深圳
文章分类
- 全部博客 (665)
- 闲话 (17)
- ruby (1)
- javascript (40)
- linux (7)
- android (22)
- 开发过程 (11)
- 哥也读读源代码 (13)
- JVM (1)
- ant (2)
- Hibernate (3)
- jboss (3)
- web service (17)
- https (4)
- java基础 (17)
- spring (7)
- servlet (3)
- 杂记 (39)
- struts2 (10)
- logback (4)
- 多线程 (2)
- 系统诊断 (9)
- UI (4)
- json (2)
- Java EE (7)
- eclipse相关 (4)
- JMS (1)
- maven (19)
- 版本管理 (7)
- sso (1)
- ci (1)
- 设计 (18)
- 戒烟 (4)
- http (9)
- 计划 (4)
- HTML5 (3)
- chrome extensions (5)
- tomcat源码阅读 (4)
- httpd (5)
- MongoDB (3)
- node (2)
最新评论
-
levin_china:
勾选了,还是找不到
用spring annotation声明的bean,当打包在jar中时,无法被扫描到 -
GGGGeek:
我用的maven-3.5.0,还没有遇到这种情况,使用jar ...
用spring annotation声明的bean,当打包在jar中时,无法被扫描到 -
GGGGeek:
受益匪浅,从组织项目结构,到技术细节,讲的很到位,只是博主不再 ...
一个多maven项目聚合的实例 -
Aaron-Joe-William:
<?xml version="1.0" ...
hibernate逆向工程 -
li272355201:
http://archive.apache.org/dist/ ...
tomcat源码阅读(一)——环境搭建
最近开发一个东西,需要用到HttpClient。这个库目前最新的版本是httpcomponents-client-4.2.1,是基于httpcomponents-core-4.2.1的,该库在版本升级过程中,发生过比较大的变动。之前这个库叫做HttpClient,现在统称为HttpComponents,拆分成了client和core,应该是重新写过
我遇到的问题,是不知道怎么配置超时时间,因为API的变化比较大,以前的方法,在这个新的版本里不好使了。
查了一下,发现超时包括ConnectionTimeout和SocketTimeout,这点和老版本一样,分别用于设置建立HTTP连接超时的时间,以及从响应中读取数据超时的时间。用
和
进行定义
变化比较大的,是设置的方法,不再提供setTimeout()之类的方法。这个版本里所有的配置,都是通过HttpParams这个组件来配置的,然后可以附着在HttpClient上,或者HttpRequest上。在HttpRequest上的设置,优先于HttpClient的全局设置
除了HttpClient和HttpRequest的HttpParams之外,还有另外2个HttpParams,最终都是聚合在ClientParamsStack里
一起提供运行时参数,有先后顺序
可以看到,requestParams是优先于clientParams的。
这段代码也有一点可以借鉴一下,当我们自己写代码,可能重复设置某一属性时,可以是将优先级高的属性放在前面,跳过后面的设置。也可以将优先级高的属性放在后面,覆盖掉前面的设置。这里用的是第一种方法,而且避免对属性的重复设置
因此在这个版本的HttpClient里,设置超时时间的方法,是这样的:
将建立HTTP连接的超时时间设置为5秒,读取响应的超时时间设置为3秒
但是实际运行后,我发现我设置的HTTP超时时间是5秒,但是实际上10秒才会超时。如果设置超时时间是2秒,就实际上4秒才会超时。实际超时时间,是我设置的2倍,为了搞清楚是怎么回事,只好打了断点跟踪进去,果然发现了问题
在DefaultClientConnectionOperator中有一行这样的代码:
这句执行之后,addresses的结果是:
[www.baidu.com/61.135.169.125, www.baidu.com/61.135.169.105]
原来通过DNS查询,我输入的域名www.baidu.com,返回了2个地址。
然后接下来的代码,会对2个地址都尝试建立连接,每次尝试的超时时间都是5秒,当所有连接都失败之后,才会抛出ConnectTimeoutException。所以实际超时时间,就成了我设置的2倍
此外,我的方法其实设置了HttpRequestInterceptor,但是实际并没有执行,因为请求拦截器的调用,是发生在建立连接成功之后的。这里在建立连接时就超时了,所以HttpRequestInterceptor并没有执行的机会
这个问题至此就定位完成了,可以总结几点:
1、CoreConnectionPNames.CONNECTION_TIMEOUT定义的是建立HTTP连接超时的时间,CoreConnectionPNames.SO_TIMEOUT定义的是读取response超时的时间
2、设置是通过HttpParams来完成的,HttpRequest的设置,优先于HttpClient的设置
3、URI如果设置为域名,那可能会解析出多个地址,那么实际超时时间,就会是设置超时时间的若干倍
4、HttpRequestInterceptor的调用,是发生在连接建立成功之后的
另外接下来说说debug相关的事情。在定位这个问题的时候,我发现InetAddress这个类,我断点跟不进去,这个类位于rt.jar的java.net包里,按理说是应该能跟进去的。
检查了一下,发现是eclipse的设置有错,Preferences-->Java-->Installed JREs里,我设置成了jre的路径,实际上要设置成jdk的路径
这样就可以跟进InetAddress这个类了,不过发现方法参数的名字都是看不见的,临时变量也看不见
这还debug个鬼啊,表示很不开心,就查了一下资料http://hllvm.group.iteye.com/group/topic/25798
原来product版的JDK,都是非debug版本的,最终生成的.class,没有包含LocalVariableTable信息,看一下jdk的编译脚本:
如果是product版的jdk,编译语句里是没有加-g参数的,所以编译出来的.class文件,只有LineNumberTable,没有LocalVariableTable,所以在debug的时候,就看不到本地变量了(包括方法参数,和临时变量)
那要解决的方法,要么自己编译一份-g的jdk,要么直接下载debug版的jdk。不过公司没有编译jdk的环境,所以我就去下了一份debug版jdk。这样debug都可以一路跟到底了,只有native method没有办法。debug jdk的下载地址:http://jdk6.java.net/download.html
总结来说,.java在编译的时候,需要加上-g参数,编译出的.class才会包含LocalVariableTable信息,以进行调试
引申一下,我们平时用Eclipse写的代码,可以直接调试,是因为Eclipse默认会让编译器带上调试信息,设置的地方在Preferences-->Java-->Compiler
所以,用Eclipse写的代码,默认就是可以直接调试的
最后,Eclipse不是用javac来编译java源码的,而是用自己的编译器,ECJ,这个编译器也支持-g参数
我遇到的问题,是不知道怎么配置超时时间,因为API的变化比较大,以前的方法,在这个新的版本里不好使了。
查了一下,发现超时包括ConnectionTimeout和SocketTimeout,这点和老版本一样,分别用于设置建立HTTP连接超时的时间,以及从响应中读取数据超时的时间。用
CoreConnectionPNames.CONNECTION_TIMEOUT
和
CoreConnectionPNames.SO_TIMEOUT
进行定义
变化比较大的,是设置的方法,不再提供setTimeout()之类的方法。这个版本里所有的配置,都是通过HttpParams这个组件来配置的,然后可以附着在HttpClient上,或者HttpRequest上。在HttpRequest上的设置,优先于HttpClient的全局设置
除了HttpClient和HttpRequest的HttpParams之外,还有另外2个HttpParams,最终都是聚合在ClientParamsStack里
public class ClientParamsStack extends AbstractHttpParams { /** The application parameter collection, or <code>null</code>. */ protected final HttpParams applicationParams; /** The client parameter collection, or <code>null</code>. */ protected final HttpParams clientParams; /** The request parameter collection, or <code>null</code>. */ protected final HttpParams requestParams; /** The override parameter collection, or <code>null</code>. */ protected final HttpParams overrideParams;
一起提供运行时参数,有先后顺序
public Object getParameter(String name) { if (name == null) { throw new IllegalArgumentException ("Parameter name must not be null."); } Object result = null; if (overrideParams != null) { result = overrideParams.getParameter(name); } if ((result == null) && (requestParams != null)) { result = requestParams.getParameter(name); } if ((result == null) && (clientParams != null)) { result = clientParams.getParameter(name); } if ((result == null) && (applicationParams != null)) { result = applicationParams.getParameter(name); } return result; }
可以看到,requestParams是优先于clientParams的。
这段代码也有一点可以借鉴一下,当我们自己写代码,可能重复设置某一属性时,可以是将优先级高的属性放在前面,跳过后面的设置。也可以将优先级高的属性放在后面,覆盖掉前面的设置。这里用的是第一种方法,而且避免对属性的重复设置
因此在这个版本的HttpClient里,设置超时时间的方法,是这样的:
HttpGet httpget = new HttpGet("http://www.baidu.com"); httpget.getParams().setParameter(CoreConnectionPNames.CONNECTION_TIMEOUT, 5000); httpget.getParams().setParameter(CoreConnectionPNames.SO_TIMEOUT, 3000);
将建立HTTP连接的超时时间设置为5秒,读取响应的超时时间设置为3秒
但是实际运行后,我发现我设置的HTTP超时时间是5秒,但是实际上10秒才会超时。如果设置超时时间是2秒,就实际上4秒才会超时。实际超时时间,是我设置的2倍,为了搞清楚是怎么回事,只好打了断点跟踪进去,果然发现了问题
在DefaultClientConnectionOperator中有一行这样的代码:
InetAddress[] addresses = resolveHostname(target.getHostName());
这句执行之后,addresses的结果是:
[www.baidu.com/61.135.169.125, www.baidu.com/61.135.169.105]
原来通过DNS查询,我输入的域名www.baidu.com,返回了2个地址。
然后接下来的代码,会对2个地址都尝试建立连接,每次尝试的超时时间都是5秒,当所有连接都失败之后,才会抛出ConnectTimeoutException。所以实际超时时间,就成了我设置的2倍
此外,我的方法其实设置了HttpRequestInterceptor,但是实际并没有执行,因为请求拦截器的调用,是发生在建立连接成功之后的。这里在建立连接时就超时了,所以HttpRequestInterceptor并没有执行的机会
这个问题至此就定位完成了,可以总结几点:
1、CoreConnectionPNames.CONNECTION_TIMEOUT定义的是建立HTTP连接超时的时间,CoreConnectionPNames.SO_TIMEOUT定义的是读取response超时的时间
2、设置是通过HttpParams来完成的,HttpRequest的设置,优先于HttpClient的设置
3、URI如果设置为域名,那可能会解析出多个地址,那么实际超时时间,就会是设置超时时间的若干倍
4、HttpRequestInterceptor的调用,是发生在连接建立成功之后的
另外接下来说说debug相关的事情。在定位这个问题的时候,我发现InetAddress这个类,我断点跟不进去,这个类位于rt.jar的java.net包里,按理说是应该能跟进去的。
检查了一下,发现是eclipse的设置有错,Preferences-->Java-->Installed JREs里,我设置成了jre的路径,实际上要设置成jdk的路径
这样就可以跟进InetAddress这个类了,不过发现方法参数的名字都是看不见的,临时变量也看不见
这还debug个鬼啊,表示很不开心,就查了一下资料http://hllvm.group.iteye.com/group/topic/25798
原来product版的JDK,都是非debug版本的,最终生成的.class,没有包含LocalVariableTable信息,看一下jdk的编译脚本:
# Any debug build should include all debug info inside the classfiles ifeq ($(VARIANT), DBG) DEBUG_CLASSFILES = true endif ifeq ($(DEBUG_CLASSFILES),true) JAVACFLAGS_COMMON += -g endif JAVACFLAGS = $(JAVACFLAGS_COMMON) $(OTHER_JAVACFLAGS) JAVAC_CMD = $(JAVAC) $(JIT_OPTION) $(JAVACFLAGS) $(LANGUAGE_VERSION) $(CLASS_VERSION)
如果是product版的jdk,编译语句里是没有加-g参数的,所以编译出来的.class文件,只有LineNumberTable,没有LocalVariableTable,所以在debug的时候,就看不到本地变量了(包括方法参数,和临时变量)
那要解决的方法,要么自己编译一份-g的jdk,要么直接下载debug版的jdk。不过公司没有编译jdk的环境,所以我就去下了一份debug版jdk。这样debug都可以一路跟到底了,只有native method没有办法。debug jdk的下载地址:http://jdk6.java.net/download.html
总结来说,.java在编译的时候,需要加上-g参数,编译出的.class才会包含LocalVariableTable信息,以进行调试
引申一下,我们平时用Eclipse写的代码,可以直接调试,是因为Eclipse默认会让编译器带上调试信息,设置的地方在Preferences-->Java-->Compiler
所以,用Eclipse写的代码,默认就是可以直接调试的
最后,Eclipse不是用javac来编译java源码的,而是用自己的编译器,ECJ,这个编译器也支持-g参数
发表评论
-
system properties和environment properties
2013-06-05 17:00 1856原来我一直都混淆了system properties和envi ... -
instance、Class、Object
2013-05-23 13:07 1917一、实例和类 所有实例都有所属的类;所有类都是Class类的 ... -
类初始化顺序,及获取资源
2013-05-22 11:07 1346最近在读tomcat的源码,涉及到各种类继承体系的初始化,还有 ... -
java的方法调用,参数是按值传递还是按引用传递
2013-05-21 16:55 1368各种语言都涉及到方法 ... -
linux下加载文件资源好纠结呀
2012-12-30 08:07 3679为了给自己添堵,我把 ... -
java io基础知识
2012-12-23 01:35 2291一、char[]、String、byte[] ... -
classloader简介
2012-11-05 13:05 1745一、基本classloader体系 默认有3个classlo ... -
System.getProperty()
2012-10-30 16:58 6811最近看tomcat源码,里面有好多System.getProp ... -
java annotation简介
2012-10-26 16:31 1731开发中自定义annotation的场景不太多,但是很多框架的源 ... -
JPDA简单总结
2012-10-12 15:33 8146我们平时经常使用的debu ... -
几种常用servlet容器开启调试的方法
2012-10-11 17:52 13801、jboss4.2.3.GA 在%JBOSS_HOME%/ ... -
转载:异常处理最佳实践
2012-08-22 17:30 1577本文系全文转载,原文 ... -
java动态代理
2012-08-16 17:16 1512常见的动态代理有2种: 第一种情况,目标类本身实现了某个接口 ... -
classpath
2012-03-25 23:14 1519classpath也是文件系统中的路径,作用是告诉类加载器要到 ... -
java集合
2011-11-27 10:28 11951、集合是一种数据结构,虽然种类不少,但是本质上就是2种,一种 ... -
JAVA类的初始化过程
2011-11-13 21:05 18151、java类中的字段,第 ...
相关推荐
本教程将深入探讨如何使用HttpClient API,以及如何在实际项目中应用。 首先,创建一个新的HttpClient实例非常简单,你可以通过`HttpClient.newBuilder()`方法来实现。这个构建器提供了丰富的选项,允许你根据需求...
httpclient-4.3.5
3. 源代码:通过阅读源代码,开发者可以理解HttpClient内部的工作机制,以及如何实现自定义功能。 六、最佳实践 1. 使用连接池:HttpClient支持连接池,可提高并发性能并减少资源消耗。 2. 正确处理异常:对可能...
httpclient 老版本依赖的jar包 包含三个文件:commons-codec-1.3.jar,commons-httpclient-3.0.jar,commons-logging-1.0.4.jar,
完全兼容jdk1.7,1.8,完整包含所有依赖包 HttpClient 4.5.3 (GA) is a maintenance release that fixes a number of defects found since 4.5.2. Please note that as of 4.4 HttpClient requires Java 1.6 or ...
本教程将详细讲解如何在.NET 6中利用HttpClient设置超时机制,确保你的请求处理在预设时间内完成,避免程序因长时间等待响应而卡死。 HttpClient类提供了发送HTTP请求的能力,同时允许开发者配置请求的多个方面,...
4. **HttpClientBuilder**: 这是一个配置工具,通过链式方法可以方便地设置HttpClient的各种参数,如超时时间、重试策略、连接池大小等。 5. **HttpClientContext**: 提供上下文信息,存储与特定请求或会话相关的...
下面,我们将深入探讨HttpClient的基础知识、调试技巧以及如何封装通用方法。 1. **HttpClient基础知识**: - HttpClient是Apache的一个开源项目,提供了强大的HTTP协议处理能力,支持GET、POST、PUT等多种HTTP...
1. **HttpClient的基本使用**:介绍HttpClient类的基本概念,包括如何创建实例,设置请求头,以及发送GET和POST请求。 2. **封装的设计**:讨论如何设计一个网络请求的通用接口或类,比如定义方法如`SendGetAsync`...
Java HTTPClient 设置超时时间和代理的方法 Java HTTPClient 是一个功能强大且灵活的 HTTP 客户端库,提供了许多实用的功能来处理 HTTP 请求。其中,设置超时时间和代理是两个非常重要的配置项,本文将详细介绍如何...
1. **创建HttpClient实例**:通过`HttpClientBuilder`可以定制配置,如设置连接超时、连接池大小等。 2. **构造请求**:使用`HttpGet`, `HttpPost`等类创建HTTP请求,可以添加请求头和请求体。 3. **执行请求**:...
4. **请求与响应**:HttpClient允许你设置请求头、参数、超时等。例如,你可以使用`setHeader()`设置请求头,`setURI()`指定请求URL。响应则通过`HttpResponse`对象获取,你可以获取响应状态码、响应头和响应体。 5...
本教程将深入讲解如何在使用HttpClient时进行精细的超时控制,这对于处理长时间运行的请求或者优化应用性能至关重要。本文档主要面向C#开发者,但对Java开发者也有一定的参考价值,因为两者都属于面向对象编程语言,...
HttpClient使用Commons Logging来记录其运行时信息,帮助开发者调试和监控HTTP请求的执行情况。 这些JAR文件在实际应用中通常是组合使用的。例如,一个Java应用程序如果需要通过HTTP与服务器进行交互,就可以依赖...
10. **性能优化**:通过配置连接超时、读写超时、连接池大小等参数,可以进一步优化HttpClient的性能。 在学习和使用HttpClient时,结合提供的示例代码,将有助于深入理解这些概念并实际应用到项目中。同时,不断...
例如,正确设置连接超时、读取超时以及连接池大小,可以避免因网络延迟导致的问题。 在实际开发中,我们可以通过Maven或Gradle等构建工具来管理和依赖httpclient.jar,确保依赖的版本一致性,并且可以方便地升级或...
1. 创建 `HttpClient` 实例,可以通过 `HttpClientBuilder` 或 `MultiThreadedHttpConnectionManager` 配置连接池和超时设置。 2. 创建 `HttpGet` 或 `HttpPost` 请求对象,设置URL和请求参数。 3. 设置请求头,例如...
然而,这个基础版本的`HttpClient`存在一些问题,如资源管理不当可能导致泄露,以及缺少重试和超时策略等。因此,对`HttpClient`进行重新封装是非常常见的实践,以解决这些问题并增加额外的功能。 重新封装的`...
在本文中,我们将深入探讨HttpClient的基本概念、用法以及如何在实际项目中应用。 HttpClient的核心类是`HttpClient`,它代表一个HTTP客户端实例,可以用来发起HTTP请求。另一个关键类是`HttpGet`和`HttpPost`,...
10. **性能优化**:通过配置连接超时、响应超时、线程池大小等参数,以及使用合适的连接管理策略,可以进一步优化HttpClient的性能。 在实际使用HttpClient时,需要根据项目需求选择合适的版本,理解其工作原理,...