问题现象
java.net.ConnectException: Connection refused
at java.net.PlainSocketImpl.socketConnect(Native Method)
at java.net.AbstractPlainSocketImpl.doConnect(AbstractPlainSocketImpl.java:327)
at java.net.AbstractPlainSocketImpl.connectToAddress(AbstractPlainSocketImpl.java:193)
at java.net.AbstractPlainSocketImpl.connect(AbstractPlainSocketImpl.java:180)
问题原因
com.springsource.org.apache.commons.httpclient-3.1.0.jar 相比commons-httpclient-3.0.jar 对 SimpleHttpConnectionManager对象做了变更,增加了alwaysClose属性,默认值为false
源码: SimpleHttpConnectionManager
//默认为false
private boolean alwaysClose = false;
/**
* The connection manager created with this constructor will try to keep the
* connection open (alive) between consecutive requests if the alwaysClose
* parameter is set to <tt>false</tt>. Otherwise the connection manager will
* always close connections upon release.
*
* @param alwaysClose if set <tt>true</tt>, the connection manager will always
* close connections upon release.
*/
public SimpleHttpConnectionManager(boolean alwaysClose) {
super();
this.alwaysClose = alwaysClose;
}
/**
* The connection manager created with this constructor will always try to keep
* the connection open (alive) between consecutive requests.
*/
public SimpleHttpConnectionManager() {
super();
}
使用HttpClient 的时候经常使用下面的代码
//旧代码实现
HttpClient client = new HttpClient(); //HttpClient 通过无参构造实现
HttpMethod method = new GetMethod("http://www.apache.org");
try {
client.executeMethod(method);
byte[] responseBody = null;
responseBody = method.getResponseBody();
} catch (HttpException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally{
method.releaseConnection();
}
//其中new HttpClient() 构造器处理过程
public HttpClient() {
this(new HttpClientParams());
}
public HttpClient(HttpClientParams params) {
super();
if (params == null) {
throw new IllegalArgumentException("Params may not be null");
}
this.params = params;
this.httpConnectionManager = null;
Class clazz = params.getConnectionManagerClass();
if (clazz != null) {
try {
this.httpConnectionManager = (HttpConnectionManager) clazz.newInstance();
} catch (Exception e) {
LOG.warn("Error instantiating connection manager class, defaulting to"
+ " SimpleHttpConnectionManager",
e);
}
}
if (this.httpConnectionManager == null) {
//这是会使用无参构造器
this.httpConnectionManager = new SimpleHttpConnectionManager();
}
if (this.httpConnectionManager != null) {
this.httpConnectionManager.getParams().setDefaults(this.params);
}
}
可见 创建SimpleHttpConnectionManager时this.httpConnectionManager = new SimpleHttpConnectionManager(); 使用无参构造器, 这个时候alwaysClose是false
当使用 method.releaseConnection(); 关闭链接时,GetMethod调用releaseConnection()实际上是调用父类同名方法,需要判断alwaysClose=true才能执行关闭,因这个原因报问题异常
HttpMethodBase源码:
public void releaseConnection() {
try {
if (this.responseStream != null) {
try {
// FYI - this may indirectly invoke responseBodyConsumed.
this.responseStream.close();
} catch (IOException ignore) {
}
}
} finally {
ensureConnectionRelease();
}
}
private void ensureConnectionRelease() {
if (responseConnection != null) {
responseConnection.releaseConnection();
responseConnection = null;
}
}
HttpConnection源码:
public void releaseConnection() {
LOG.trace("enter HttpConnection.releaseConnection()");
if (locked) {
LOG.debug("Connection is locked. Call to releaseConnection() ignored.");
} else if (httpConnectionManager != null) {
LOG.debug("Releasing connection back to connection manager.");
httpConnectionManager.releaseConnection(this);
} else {
LOG.warn("HttpConnectionManager is null. Connection cannot be released.");
}
}
SimpleHttpConnectionManager源码:
public void releaseConnection(HttpConnection conn) {
if (conn != httpConnection) {
throw new IllegalStateException("Unexpected release of an unknown connection.");
}
//这里判断alwaysClose=true的时候才会close,但是现在是false 所以无法正常关闭
if (this.alwaysClose) {
httpConnection.close();
} else {
// make sure the connection is reuseable
finishLastResponse(httpConnection);
}
inUse = false;
// track the time the connection was made idle
idleStartTime = System.currentTimeMillis();
}
处理方式
因为com.springsource.org.apache.commons.httpclient-3.1.0.jar 相比commons-httpclient-3.0.jar 对 SimpleHttpConnectionManager对象做了变更
构造 HttpClient的方式不同,建议使用 HttpClient httpClient = new HttpClient(new HttpClientParams(),new SimpleHttpConnectionManager(true));