目前幾套系統中主要使用的hessian進行遠程調用webservice服務的有hessian的HessianProxyFactory(com.caucho.hessian.client.HessianProxyFactory)和spring的HessianProxyFactoryBean(org.springframework.remoting.caucho.HessianProxyFactoryBean).
1.HessianProxyFactory
查看HessianProxyFactory源碼后發現,hessian在創建http請求連接webservice服務并沒有對連接超時進行相關的參數設置,所以當網絡出現問題就會造成整個hessian處理的阻塞,進而阻塞整個線程后續的處理
以下是HessianProxyFactory對連接處理的源碼
protected URLConnection openConnection(URL url)
throws IOException
{
URLConnection conn = url.openConnection();
conn.setDoOutput(true);
if (_readTimeout > 0) {
try {
conn.setReadTimeout((int) _readTimeout);
} catch (Throwable e) {
}
}
conn.setRequestProperty("Content-Type", "x-application/hessian");
if (_basicAuth != null)
conn.setRequestProperty("Authorization", _basicAuth);
else if (_user != null && _password != null) {
_basicAuth = "Basic " + base64(_user + ":" + _password);
conn.setRequestProperty("Authorization", _basicAuth);
}
return conn;
}
所以我們針對此邏輯繼承并重寫該openConnection方法,在創建http連接的時候通過設置連接超時時間來解決因網絡問題阻塞程序繼續的問題
public class MyHessianProxyFactory extends HessianProxyFactory {
private int connectTimeOut = 10000;
private int readTimeOut = 10000;
public int getConnectTimeOut() {
return connectTimeOut;
}
public void setConnectTimeOut(int connectTimeOut) {
this.connectTimeOut = connectTimeOut;
}
public int getReadTimeOut() {
return readTimeOut;
}
public void setReadTimeOut(int readTimeOut) {
this.readTimeOut = readTimeOut;
}
protected URLConnection openConnection(URL url) throws IOException {
URLConnection conn = url.openConnection();
conn.setDoOutput(true);
if (this.connectTimeOut > 0) {
conn.setConnectTimeout(this.connectTimeOut);
}
if (this.readTimeOut > 0) {
conn.setReadTimeout(this.readTimeOut);
}
conn.setRequestProperty("Content-Type", "x-application/hessian");
if (_basicAuth != null)
conn.setRequestProperty("Authorization", _basicAuth);
else if (_user != null && _password != null) {
_basicAuth = "Basic " + base64(_user + ":" + _password);
conn.setRequestProperty("Authorization", _basicAuth);
}
return conn;
}
}
2.HessianProxyFactoryBean
查看spring的HessianProxyFactoryBean源碼發現,它在封裝hessian是直接創建一個HessianProxyFactory實例,然后利用該實例完成創建遠程服務
public class HessianProxyFactoryBean extends HessianClientInterceptor implements FactoryBean {
private Object serviceProxy;
public void afterPropertiesSet() {
super.afterPropertiesSet();
this.serviceProxy = ProxyFactory.getProxy(getServiceInterface(), this);
}
public Object getObject() {
return this.serviceProxy;
}
public Class getObjectType() {
return getServiceInterface();
}
public boolean isSingleton() {
return true;
}
}
所以對此的解決方法與上面差不多,繼承HessianProxyFactoryBean然后加入相應的連接超時和讀取超時的變量,重寫afterPropertiesSet方法,并且同時完成上面第一步對HessianProxyFactory的改造,這樣就能保證連接遠程webserver服務器時不會因為網絡原因阻塞程序的執行
public class MyHessianProxyFactoryBean extends HessianProxyFactoryBean {
private MyHessianProxyFactory proxyFactory = new MyHessianProxyFactory();
private int readTimeOut = 10000;
private int connectTimeOut = 10000;
public int getReadTimeOut() {
return readTimeOut;
}
public void setReadTimeOut(int readTimeOut) {
this.readTimeOut = readTimeOut;
}
public int getConnectTimeOut() {
return connectTimeOut;
}
public void setConnectTimeOut(int connectTimeOut) {
this.connectTimeOut = connectTimeOut;
}
public void afterPropertiesSet() {
proxyFactory.setReadTimeout(readTimeOut);
proxyFactory.setConnectTimeOut(connectTimeOut);
setProxyFactory(proxyFactory);
super.afterPropertiesSet();
}
}