當前位置:
首頁 > 知識 > 基於springmvc的hessian調用原理淺析

基於springmvc的hessian調用原理淺析


一、客戶端

1、構造(初始化)

由客戶端的配置文件隨容器的啟動而進行初始化,配置文件如下:


xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"

xsi:schemaLocation="http://www.springframework.org/schema/beans

http://www.springframework.org/schema/beans/spring-beans.xsd

http://www.springframework.org/schema/context

http://www.springframework.org/schema/context/spring-context.xsd">

class="org.springframework.remoting.caucho.HessianProxyFactoryBean">

${app_server_path}

com.avatarmind.server.service.ApplicationService

先放張類關係圖:

基於springmvc的hessian調用原理淺析

根據spring生命周期可知,容器初始化,會調用InitializingBean的afterPropertiesSet()方法,

而HessianProxyFactoryBean類實現了InitializingBean介面並重寫了afterPropertiesSet()方法。

所以主要流程為:

1)、HessianProxyFactoryBean的afterPropertiesSet()

2)、HessianClientInterceptor的afterPropertiesSet()

3)、HessianClientInterceptor的prepare()

4)、HessianClientInterceptor的createHessianProxy(HessianProxyFactory proxyFactory)

5)、HessianProxyFactory的create(Class api, String urlName, ClassLoader loader)


public Object create(Class api, URL url, ClassLoader loader)

{

if (api == null)

throw new NullPointerException("api must not be null for HessianProxyFactory.create()");

InvocationHandler handler = null;

handler = new HessianProxy(url, this, api);

return Proxy.newProxyInstance(loader,

new Class[] { api,

HessianRemoteObject.class },

handler);

}

整個流程最終就是為服務介面生成代理類。

2、使用介面調用服務

具體的方法調用我就不寫了,不知道的可以看我以前寫的hessian的基本使用。

由public class HessianProxy implements InvocationHandler, Serializable和構造的第 5)里的代碼可知

介面的調用會轉到HessianProxy的invoke(Object proxy, Method method, Object []args)方法里。

具體的代碼如下,有些細節我也不是很懂,好像就是序列化、發送請求(conn = sendRequest(mangleName, args);)、

反序列化,還有校驗和處理其他方法。


public Object invoke(Object proxy, Method method, Object []args)

throws Throwable

{

String mangleName;

synchronized (_mangleMap) {

mangleName = _mangleMap.get(method);

}

if (mangleName == null) {

String methodName = method.getName();

Class []params = method.getParameterTypes();

// equals and hashCode are special cased

if (methodName.equals("equals")

&& params.length == 1 && params[0].equals(Object.class)) {

Object value = args[0];

if (value == null || ! Proxy.isProxyClass(value.getClass()))

return Boolean.FALSE;

Object proxyHandler = Proxy.getInvocationHandler(value);

if (! (proxyHandler instanceof HessianProxy))

return Boolean.FALSE;

HessianProxy handler = (HessianProxy) proxyHandler;

return new Boolean(_url.equals(handler.getURL()));

}

else if (methodName.equals("hashCode") && params.length == 0)

return new Integer(_url.hashCode());

else if (methodName.equals("getHessianType"))

return proxy.getClass().getInterfaces()[0].getName();

else if (methodName.equals("getHessianURL"))

return _url.toString();

else if (methodName.equals("toString") && params.length == 0)

return "HessianProxy[" + _url + "]";

if (! _factory.isOverloadEnabled())

mangleName = method.getName();

else

mangleName = mangleName(method);

synchronized (_mangleMap) {

_mangleMap.put(method, mangleName);

}

}

InputStream is = null;

HessianConnection conn = null;

try {

if (log.isLoggable(Level.FINER))

log.finer("Hessian[" + _url + "] calling " + mangleName);

// 調用服務端

conn = sendRequest(mangleName, args);

is = getInputStream(conn);

if (log.isLoggable(Level.FINEST)) {

PrintWriter dbg = new PrintWriter(new LogWriter(log));

HessianDebugInputStream dIs

= new HessianDebugInputStream(is, dbg);

dIs.startTop2();

is = dIs;

}

AbstractHessianInput in;

int code = is.read();

if (code == "H") {

int major = is.read();

int minor = is.read();

in = _factory.getHessian2Input(is);

Object value = in.readReply(method.getReturnType());

return value;

}

else if (code == "r") {

int major = is.read();

int minor = is.read();

in = _factory.getHessianInput(is);

in.startReplyBody();

Object value = in.readObject(method.getReturnType());

if (value instanceof InputStream) {

value = new ResultInputStream(conn, is, in, (InputStream) value);

is = null;

conn = null;

}

else

in.completeReply();

return value;

}

else

throw new HessianProtocolException(""" + (char) code + "" is an unknown code");

} catch (HessianProtocolException e) {

throw new HessianRuntimeException(e);

} finally {

try {

if (is != null)

is.close();

} catch (Exception e) {

log.log(Level.FINE, e.toString(), e);

}

try {

if (conn != null)

conn.destroy();

} catch (Exception e) {

log.log(Level.FINE, e.toString(), e);

}

}

}

二、服務端

1、構造(初始化)

配置文件:


xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:mvc="http://www.springframework.org/schema/mvc"

xmlns:context="http://www.springframework.org/schema/context"

xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd

http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd

http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">

class="org.springframework.remoting.caucho.HessianServiceExporter">

同理:

基於springmvc的hessian調用原理淺析

主要流程:

1)、HessianExporter的afterPropertiesSet()

2)、HessianExporter的prepare()

3)、RemoteExporter的getProxyForService()

流程主要是生成HessianSkeleton類的對象。

因為配置文件的bean的name帶 / 符號,所以會被BeanNameUrlHandlerMapping進行映射處理。

2、被調用

由於基於mvc,所以請求會先到DispatcherServlet的doDispatch方法,然後根據路徑獲取handler,

因此服務的入口為HessianServiceExporter的handleRequest()方法。


public void handleRequest(HttpServletRequest request, HttpServletResponse response)

throws ServletException, IOException {

// 驗證服務是否啟動成功的地方

if (!"POST".equals(request.getMethod())) {

throw new HttpRequestMethodNotSupportedException(request.getMethod(),

new String[] {"POST"}, "HessianServiceExporter only supports POST requests");

}

response.setContentType(CONTENT_TYPE_HESSIAN);

try {

// 調用

invoke(request.getInputStream(), response.getOutputStream());

}

catch (Throwable ex) {

throw new NestedServletException("Hessian skeleton invocation failed", ex);

}

}

流程:

1)、HessianServiceExporter的handleRequest()

2)、HessianExporter的invoke(InputStream inputStream, OutputStream outputStream)

3)、HessianExporter的doInvoke(HessianSkeleton skeleton, InputStream inputStream, OutputStream outputStream)

核心代碼:skeleton.invoke(in, out);

4)、HessianSkeleton的invoke()

核心代碼:result = method.invoke(service, values);

利用反射調用具體的實現方法。中間摻雜著反序列化,校驗,序列化的其他方法。

基於springmvc的hessian調用原理淺析


更多優質內容推薦:

有錢任性,某公司豪擲500萬幫助20左右年輕人找工作,起因是做善良的人:

http://www.ujiuye.com/zt/jyfc/?wt.bd=zdy35845tt

學安卓,免學費!50天興趣課程等你來搶!

http://www.ujiuye.com/xydt/2017/13042.html?wt.bd=zdy35845tt

喜歡這篇文章嗎?立刻分享出去讓更多人知道吧!

本站內容充實豐富,博大精深,小編精選每日熱門資訊,隨時更新,點擊「搶先收到最新資訊」瀏覽吧!


請您繼續閱讀更多來自 IT優就業 的精彩文章:

「租賃」這頭豬,怎麼就趴上「共享」這個風口上了呢?
CSS 樣式書寫規範
nodejs 構建本地web測試伺服器 以及 解決訪問靜態資源的問題!

TAG:IT優就業 |

您可能感興趣

necp_client_action系統調用中的堆溢出漏洞分析
SpringCloud之服務提供與調用(Ribbon,Feign)
使用 python 調用 echart 畫圖
python調用api介面
使用redis來調用iptables,封禁惡意IP
透過現象看原理:詳解 Spring 中 Bean 的 this 調用導致 AOP 失效的原因
c井動態調用WebService
python訓練mask rcnn模型&&C++調用訓練好的模型——基於opencv4.0
OpenCV調用TensorFlow是什麼意思
dubbo+zipkin調用鏈監控
通過調用Windows命令,將chm 文件轉換為html 文件
Python 調用 Micro 宏自動解析 Nmon 文件進行數據歸檔
關於如何使用webpack命令行傳入變數,並通過process.env來調用
Asp.Net Core使用SignalR進行服務間調用
jQuery UI 小部件(Widget)方法調用
C/C++ 使用 TensorFlow 預訓練好模型——間接調用 Python 實現
加入Transformer-XL,這個PyTorch包能調用各種NLP預訓練模型
如何用Ptrace攔截並模擬Linux系統調用
利用Zipkin追蹤Mysql資料庫調用鏈
Alexa應用開發者將可免費調用8種Amazon Polly自然語音