⑴ 怎麼調用hessian介面 spring
1.Spring中除了提供HTTP調用器方式的遠程調用,還對第三方的遠程調用實現提供了支持,其中提供了對的支持。
Hessian是由Caocho公司發布的一個輕量級的二進制協議遠程調用實現方案,Hessian也是基於HTTP協議的,其工作原理如下:
(1).客戶端:
a.發送遠程調用請求:
客戶端程序—>發送遠程調用請求—>Hessian客戶端攔截器—>封裝遠程調用請求—>Hessian代理—>通過HTTP協議發送遠程請求代理到服務端。
b.接收遠程調用響應:
遠程調用結果—>HTTP響應—>客戶端。
(1).服務端:
a.接收遠程調用請求:
遠程調用HTTP請求—>HessianServiceExporter接收請求—>HessianExporter將遠程調用對象封裝為HessianSkeleton框架—> HessianSkeleton處理遠程調用請求。
b.返回遠程調用響應:
HessianSkeleton封裝遠程調用處理結果—>HTTP響應—>客戶端。
本文章通過分析Spring對Hessian支持的相關源碼,了解Spring對Hessian支持的具體實現。
2.Hessian的客戶端配置:
Hessian的客戶端需要做類似如下的配置:
[xhtml] view plain
<bean id=」hessianProxy」 class=」org.springframework.remoting.caucho.HessianProxyFactoryBean」>
<property name=」serviceUrl」>
<value>http://hostAddress:8080/serviceUrl</value>
</property>
<property name=」serviceInterface」>
<value>遠程調用服務介面</value>
]</property>
</bean>
和HTTP調用器的配置類似,都需要配置遠程調用請求的url,這個url要和服務端的url一致,Spring通過DispatcherServlet找到服務端對於的請求url。
HessianProxyFactoryBean是Spring中管理Hessian客戶端的IoC容器,主要負責產生服務端遠程調用代理和對客戶端遠程調用的攔截器設置。
3.HessianProxyFactoryBean:
HessianProxyFactoryBean生成遠程調用代理和客戶端遠程調用攔截器設置,其源碼如下:
[java] view plain
public class HessianProxyFactoryBean extends HessianClientInterceptor implements FactoryBean<Object> {
//遠程調用代理對象
private Object serviceProxy;
//Spring IoC容器依賴注入完成後的回調方法
public void afterPropertiesSet() {
//首先調用父類HessianClientInterceptor的回調方法
super.afterPropertiesSet();
//創建遠程調用代理對象並設置攔截器,注意這個this參數,因為//HessianProxyFactoryBean繼承HessianClientInterceptor,因此其本身也
//是Hassien客戶端攔截器
this.serviceProxy = new ProxyFactory(getServiceInterface(), this).getProxy(getBeanClassLoader());
}
//Spring IoC容器的介面FactoryBean產生對象的方法,客戶端通過該方法獲取被管
//理的遠程調用代理
public Object getObject() {
return this.serviceProxy;
}
//獲取對象的類型
public Class<?> getObjectType() {
return getServiceInterface();
}
//對象是否是單態類型,Spring默認管理的對象都是單態模式
public boolean isSingleton() {
return true;
}
}
HessianProxyFactoryBean最核心的功能就是在IoC容器回調方法中產生遠程調用代理對象,在產生遠程調用代理對象時,將代理對象的攔截器設置為其父類HessianClientInterceptor。
4.HessianClientInterceptor攔截客戶端的遠程調用請求:
HessianClientInterceptor對客戶端的遠程調用進行攔截,為客戶端的遠程調用創建Hessian代理,通過Hessian代理調用服務端遠程調用對象,其源碼如下:
[java] view plain
public class HessianClientInterceptor extends UrlBasedRemoteAccessor implements MethodInterceptor {
//創建Hessiann代理工廠
private HessianProxyFactory proxyFactory = new HessianProxyFactory();
//Hessian代理
private Object hessianProxy;
//設置Hessian代理工廠
public void setProxyFactory(HessianProxyFactory proxyFactory) {
this.proxyFactory = (proxyFactory != null ? proxyFactory : new HessianProxyFactory());
}
//設置Hessian序列化工廠
public void setSerializerFactory(SerializerFactory serializerFactory) {
this.proxyFactory.setSerializerFactory(serializerFactory);
}
//設置Hessian是否發送java集合類型對象
public void setSendCollectionType(boolean sendCollectionType) {
this.proxyFactory.getSerializerFactory().setSendCollectionType(sendCollectionType);
}
//設置遠程調用時是否重載方法
public void setOverloadEnabled(boolean overloadEnabled) {
this.proxyFactory.setOverloadEnabled(overloadEnabled);
}
//設置遠程調用用戶名
public void setUsername(String username) {
this.proxyFactory.setUser(username);
}
//設置遠程調用密碼
public void setPassword(String password) {
this.proxyFactory.setPassword(password);
}
//設置是否使用Hessian的Debug調試模式
public void setDebug(boolean debug) {
this.proxyFactory.setDebug(debug);
}
//設置是否使用chunked埠發送Hessian請求
public void setChunkedPost(boolean chunkedPost) {
this.proxyFactory.setChunkedPost(chunkedPost);
}
//設置Hessian等待響應的超時時長
public void setReadTimeout(long timeout) {
this.proxyFactory.setReadTimeout(timeout);
}
//設置是否使用Hessain版本2協議解析請求和響應
public void setHessian2(boolean hessian2) {
this.proxyFactory.setHessian2Request(hessian2);
this.proxyFactory.setHessian2Reply(hessian2);
}
//設置是否使用Hessian版本2協議解析請求
public void setHessian2Request(boolean hessian2) {
this.proxyFactory.setHessian2Request(hessian2);
}
//設置是否使用Hessian版本2協議解析響應
public void setHessian2Reply(boolean hessian2) {
this.proxyFactory.setHessian2Reply(hessian2);
}
//子類HessianProxyFactoryBean的回調方法調用此回調方法
public void afterPropertiesSet() {
//調用其父類UrlBasedRemoteAccessor的回調方法獲取客戶端配置的請求url
super.afterPropertiesSet();
//初始化Hessian代理
prepare();
}
//初始化Hessian代理
public void prepare() throws RemoteLookupFailureException {
try {
//創建Hessian代理
this.hessianProxy = createHessianProxy(this.proxyFactory);
}
catch (MalformedURLException ex) {
throw new RemoteLookupFailureException("Service URL [" + getServiceUrl() + "] is invalid", ex);
}
}
//創建Hessian代理
protected Object createHessianProxy(HessianProxyFactory proxyFactory) throws MalformedURLException {
Assert.notNull(getServiceInterface(), "'serviceInterface' is required");
//使用Hessian代理工廠創建Hessian代理
return proxyFactory.create(getServiceInterface(), getServiceUrl());
}
//攔截器客戶端請求的方法
public Object invoke(MethodInvocation invocation) throws Throwable {
if (this.hessianProxy == null) {
throw new IllegalStateException("HessianClientInterceptor is not properly initialized - " +
"invoke 'prepare' before attempting any operations");
}
//獲取當前環境中線程類載入器
ClassLoader originalClassLoader = ();
try {
//調用Hessian代理的方法,是Hessian遠程調用的入口方法,使用JDK反射機制
return invocation.getMethod().invoke(this.hessianProxy, invocation.getArguments());
}
//處理Hessian遠程調用中的異常
catch (InvocationTargetException ex) {
Throwable targetEx = ex.getTargetException();
if (targetEx instanceof InvocationTargetException) {
targetEx = ((InvocationTargetException) targetEx).getTargetException();
}
if (targetEx instanceof HessianConnectionException) {
throw convertHessianAccessException(targetEx);
}
else if (targetEx instanceof HessianException || targetEx instanceof HessianRuntimeException) {
Throwable cause = targetEx.getCause();
throw convertHessianAccessException(cause != null ? cause : targetEx);
}
else if (targetEx instanceof UndeclaredThrowableException) {
UndeclaredThrowableException utex = (UndeclaredThrowableException) targetEx;
throw convertHessianAccessException(utex.getUndeclaredThrowable());
}
else {
throw targetEx;
}
}
catch (Throwable ex) {
throw new RemoteProxyFailureException(
"Failed to invoke Hessian proxy for remote service [" + getServiceUrl() + "]", ex);
}
//重置類載入器
finally {
resetThreadContextClassLoader(originalClassLoader);
}
}
//將Hessian異常轉換為Spring遠程調用異常
protected RemoteAccessException convertHessianAccessException(Throwable ex) {
if (ex instanceof HessianConnectionException || ex instanceof ConnectException) {
return new RemoteConnectFailureException(
"Cannot connect to Hessian remote service at [" + getServiceUrl() + "]", ex);
}
else {
return new RemoteAccessException(
"Cannot access Hessian remote service at [" + getServiceUrl() + "]", ex);
}
}
}
通過上面對HessianClientInterceptor的源碼分析,我們可以看到Hessian客戶端攔截器提供的最重要的方法是對遠程調用攔截的方法invoke,在該方法中使用JDK的反射機制調用Hessian代理對象的指定方法。而Hessian代理是由Hessain代理器工廠HessianProxyFactory產生的,這個Hessian代理器工廠是有Hessian提供的。