Hessian 源碼簡單分析

Hessian 源碼簡單分析

Hessian 是一個rpc框架, 我們需要先寫一個服務端, 然后在客戶端遠程的調用它即可。

?

服務端:

服務端通常和spring 做集成。

首先寫一個接口:

public interface HelloService {    
void sayHello(String name);
}

然后一個實現,實現使用@Service("helloService") ? 實現spring bean注冊。

@Service("helloService")    
public class HelloServiceImpl implements HelloService {
@Override
public void sayHello(String name) {
System.out.println("Hello " + name + "!");
}
}

spring xml配置中,通過org.springframework.remoting.caucho.HessianServiceExporter 完成服務的暴露:
<!-- Name保持與web.xml中的一致,web.xml下文中描述 -->
<bean name="HelloServiceExporter"
class="org.springframework.remoting.caucho.HessianServiceExporter">
<!-- service的ref與HelloServiceImpl中@Service中配置的一致 -->
<property name="service" ref="helloService" />
<!-- 接口的路徑 -->
<property name="serviceInterface"
value="hessian.HelloService" />
</bean>
web.xml 的關鍵配置:
<servlet>
<!-- servlet-name保持與spring-hessian.xml中一致 -->
<servlet-name>HelloServiceExporter</servlet-name>
<servlet-class>org.springframework.web.context.support.HttpRequestHandlerServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>HelloServiceExporter</servlet-name>
<url-pattern>/HelloService</url-pattern>
</servlet-mapping>
HessianServiceExporter 有兩個關鍵的屬性: serviceInterface 和 service 
serviceInterface 是必須是一個接口,也就是服務,值必須是一個接口的全路徑FQN
service 是具體的實現bean,是一個實例的引用

HttpRequestHandlerServlet extends HttpServlet
HttpRequestHandlerServlet 的關鍵代碼是:
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
LocaleContextHolder.setLocale(request.getLocale());

try {
this.target.handleRequest(request, response);
} catch (HttpRequestMethodNotSupportedException var8) {
String[] supportedMethods = var8.getSupportedMethods();
if (supportedMethods != null) {
response.setHeader("Allow", StringUtils.arrayToDelimitedString(supportedMethods, ", "));
}

response.sendError(405, var8.getMessage());
} finally {
LocaleContextHolder.resetLocaleContext();
}

}

其實就是調用了 HessianServiceExporter 的handler 方法,HessianServiceExporter 的關鍵代碼是:
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");
} else {
response.setContentType("application/x-hessian");

try {
this.invoke(request.getInputStream(), response.getOutputStream());
} catch (Throwable var4) {
throw new NestedServletException("Hessian skeleton invocation failed", var4);
}
}
}

代碼關系是:

HessianServiceExporter extends HessianExporter implements HttpRequestHandler
HessianExporter extends RemoteExporter implements InitializingBean

HessianExporter has a HessianSkeleton
HessianSkeleton extends AbstractSkeleton

HessianSkeleton 的invoke 方法實現關鍵的request處理

具體來說:

HessianInput extends AbstractHessianInput
HessianOutput extends AbstractHessianOutput

HessianInput 有提供 readHeader、readMethod、readMethodArgLength、readBytes、readInt、readLong、readString/readDouble/readObject、 readCall、 startCall、completeCall、readReply、startReply、completeReply 等方法

HessianOutput 有writeBytes Int long , Double,String, Object, writeReply 等方法

req 獲取 InputStream, res 獲取OutputStream。

HessianInput 從 req 中讀取 方法,參數, 然后method 反射調用 service, 然后通過 HessianOutput 寫回結果

in.completeCall();
out.writeReply(result); // 發送處理結果到 遠程客戶端
out.close();

這樣, 就完成了服務端的編寫,看起來還是比較簡單的。


客戶端:

因為Hessian服務端暴露的服務實際上是一個基于http實現通信的。 故我們需要通過http 調用?Hessian。

客戶端可以是一個web應用,也可以是一個簡單的main:

方式1,通過HessianProxyFactory:
public static void main(String[] args) {    
try {
String url = "http://localhost:8080/HelloService";
HessianProxyFactory factory = new HessianProxyFactory();
HelloService helloService = (HelloService) factory.create(
HelloService.class, url);
helloService.sayHello("張三");
} catch (Exception e) {
e.printStackTrace();
}
}
稍微查看一下源碼,我們就會發現:

HessianProxy implements InvocationHandler, Serializable 可見 hessian 是使用jdk 動態代理實現的, 故我們需要一個接口

HessianURLConnection extends AbstractHessianConnection implements HessianConnection

HessianURLConnection 有一個 java.net.URLConnection ?, 可見Hessian 的通信主要就是通過http, 具體是 URLConnection實現的。

HessianProxy has a HessianProxyFactory
HessianProxyFactory has a HessianConnectionFactory
HessianProxyFactory 用來獲取conn: conn = this._factory.getConnectionFactory().open(this._url);
HessianProxy relate to HessianConnection

?

?具體來說是這樣的:

create 返回的是一個代理, return Proxy.newProxyInstance(loader, new Class[]{api, HessianRemoteObject.class}, handler);

HessianProxy 的invoke 是關鍵:


sendRequest 方法
os = conn.getOutputStream(); 通過conn 返回OutputStream

OutputStream os 強制轉換為?AbstractHessianOutput, 然后

out.call(methodName, args); // 發送數據到 遠程服務端
out.flush();
conn.sendRequest(); // 返回一個statusMessage?
is = httpConn.getInputStream(); // 通過conn獲取InputStream,


conn = this.sendRequest(mangleName, args);
is = conn.getInputStream(); // 通過sendRequest發送完數據后, 就可以通過conn 獲取遠程的返回的數據了。

InputStream的is 轉換為 AbstractHessianInput 后, 然后就可以 readObject
value = in.readObject(method.getReturnType()); // readObject 最終返回了 遠程調用的結果。 至此,單次 rpc 結束

?

?

方式2,通過HessianProxyFactoryBean:
public static void main(String[] args) {
ClassPathXmlApplicationContext classPathXmlApplicationContext = new ClassPathXmlApplicationContext("spring-servlet.xml");
HelloService ser = (HelloService) classPathXmlApplicationContext.getBean("testHessianService");
ser.sayHello("lk AA");
}

其實也就是把前面的HessianProxyFactory 集成到了spring,封裝成了bean

HessianProxy implements InvocationHandler, Serializable 可見 hessian 是使用jdk 動態代理實現的, 故我們需要一個接口

HessianURLConnection extends AbstractHessianConnection implements HessianConnection

HessianProxyFactoryBean extends HessianClientInterceptor implements FactoryBean<Object>

HessianClientInterceptor extends UrlBasedRemoteAccessor implements MethodInterceptor

HessianClientInterceptor has a HessianProxyFactory

HessianClientInterceptor 定義hessianProxy:有一個屬性: private Class serviceInterface;
serviceInterface 定義serviceInterface:有一個屬性: private Class serviceInterface;
UrlBasedRemoteAccessor 定義serviceUrl:有一個屬性: private String serviceUrl;

hessianProxy 是通過proxyFactory(也就是HessianProxyFactory)創建, 可見, HessianProxyFactoryBean 還是通過HessianProxyFactory來完成的主要工作的。

簡單說,其實就是 spring 通過反射的調用proxyFactory 的遠程方法。

?

當然,實際使用的時候, 我們不會使用?ClassPathXmlApplicationContext, 它僅僅是在測試環境中使用。

posted on 2017-08-15 13:10 CanntBelieve 閱讀(...) 評論(...) 編輯 收藏

轉載于:https://www.cnblogs.com/FlyAway2013/p/7364576.html

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/371492.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/371492.shtml
英文地址,請注明出處:http://en.pswp.cn/news/371492.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Java開發人員應該知道的三件事

對于那些長期關注JavaOne 2012會議的讀者來說&#xff0c;這是一篇有趣的文章。 我最近對Java冠軍Heinz Kabutz的采訪引起了我的注意&#xff1b; 包括他的Java內存難題程序&#xff0c;從Java內存管理的角度來看&#xff0c;這很有啟發性。 采訪中有一個特別的部分吸引了我的注…

android怎么垂直居中且靠右,placeholder 靠右垂直居中/位置兼容

1.input輸入框文字靠右垂直居中。2.placehoder提示同樣靠右垂直居中。( placeholder是HTML5 input的新屬性&#xff0c;英文意思是占位符&#xff0c;它一般表示input輸入框的默認提示值。)css代碼input {text-align: right;font-size:0.3rem;width:100%;height:0.78rem;line-…

Python-Matplotlib 18 注釋

Python-Matplotlib 18 注釋 EG1: import numpy as np import matplotlib.pyplot as plty np.arange(-5, 6,1) plt.plot(y, y*y) plt.annotate(Annotate , xy(0,1) , xytext(0,5) ,arrowpropsdict(facecolorr , frac0.2 ))plt.show()轉載于:https://www.cnblogs.com/zsr0401/p/…

while和for循環

循環結構圖&#xff1a; 循環結構主要分為兩種&#xff1a;有while和for兩種循環&#xff0c;while又分為do{...}while和while{...},do...while表示先執行后判斷&#xff0c;而while循壞表示先判斷后執行&#xff0c;如果循環條件都不滿足的情況下&#xff0c;do...while至少執…

通過beforeClass和afterClass設置增強Spring Test Framework

如何允許實例方法作為JUnit BeforeClass行為運行 JUnit允許您在所有測試方法調用之前和之后一次在類級別上設置方法。 但是&#xff0c;通過有意設計&#xff0c;他們將其限制為僅使用BeforeClass和AfterClass批注的靜態方法。 例如&#xff0c;此簡單的演示顯示了典型的Junit設…

華為鴻蒙出來正當時,關于華為鴻蒙操作系統,中興率先表態

原標題&#xff1a;關于華為鴻蒙操作系統&#xff0c;中興率先表態 來源&#xff1a;科技數碼迷進入2021年之后中興這個品牌的存在感越來越強了&#xff0c;并且還學會了借勢營銷。每當國內智能手機領域有大事之時總會看到中興或紅魔手機的身影。這說明在5G過渡期中興要借個機會…

條件變量(Condition Variable)詳解

轉載于&#xff1a;http://blog.csdn.net/erickhuang1989/article/details/8754357 條件變量(Condtion Variable)是在多線程程序中用來實現“等待->喚醒”邏輯常用的方法。舉個簡單的例子&#xff0c;應用程序A中包含兩個線程t1和t2。t1需要在bool變量test_cond為true時才能…

C++中的深拷貝和淺拷貝 QT中的深拷貝,淺拷貝和隱式共享

下面是C中定義的深&#xff0c;淺拷貝 當用一個已初始化過了的自定義類類型對象去初始化另一個新構造的對象的時候&#xff0c;拷貝構造函數就會被自動調用。也就是說&#xff0c;當類的對象需要拷貝時&#xff0c;拷貝構造函數將會被調用。以下情況都會調用拷貝構造函數&#…

使用PowerMock模擬構造函數

我認為&#xff0c;依賴項注入的主要好處之一是可以將模擬和/或存根對象注入代碼中&#xff0c;以提高可測試性&#xff0c;增加測試覆蓋率并編寫更好&#xff0c;更有意義的測試。 但是&#xff0c;有時候您會遇到一些不使用依賴注入的傳統代碼&#xff0c;而是通過組合而不是…

Brackets (區間DP)

個人心得&#xff1a;今天就做了這些區間DP&#xff0c;這一題開始想用最長子序列那些套路的&#xff0c;后面發現不滿足無后效性的問題&#xff0c;即&#xff08;&#xff0c;&#xff09;的配對 對結果有一定的影響&#xff0c;后面想著就用上一題的思想就慢慢的從小一步一步…

android生成aar無效,android studio生成aar包并在其他工程引用aar包的方法

1.aar包是android studio下打包android工程中src、res、lib后生成的aar文件&#xff0c;aar包導入其他android studio 工程后&#xff0c;其他工程可以方便引用源碼和資源文件2.生成aar包步驟&#xff1a;①.用android studio打開一個工程&#xff0c;然后新建一個Module&#…

《劍指offer》— JavaScript(3)從尾到頭打印鏈表

從尾到頭打印鏈表 題目描述 輸入一個鏈表&#xff0c;從尾到頭打印鏈表每個節點的值。 實現代碼 /*function ListNode(x){this.val x;this.next null; }*/ function printListFromTailToHead(head) {var res[];while(head){res.unshift(head.val);headhead.next;}return res;…

JUnit測試Spring Service和DAO(帶有內存數據庫)

這篇文章描述了如何為Spring Web Application的Services和DAO實現JUnit測試。 它建立在Spring MVC-Service-DAO-Persistence Architecture Example的基礎上 。 從Github的Spring-Web-JPA-Testing目錄中可以找到該示例。 提醒 測試裝置 –固定狀態&#xff0c;用作運行測試的基…

c# 正則獲取html標簽內容,c# – 使用正則表達式在多個HTML標記之間獲取文本

使用正則表達式,我希望能夠在多個DIV標記之間獲取文本.例如,以下內容&#xff1a;first html taganother tag輸出&#xff1a;first html taganother tag我使用的正則表達式模式只匹配我的最后一個div標簽并錯過了第一個.碼&#xff1a;static void Main(string[] args){string…

Android之外部存儲(SD卡)

*手機的外部存儲空間&#xff0c;這個我們可以理解成電腦的外接移動硬盤&#xff0c;U盤也行。所有的Android設備都有兩個文件存儲區域&#xff1a;“內部”和“外部”存儲器。這兩個名稱來自早期的Android&#xff0c;當時大多數設備都提供內置的固定的內存&#xff08;內置存…

通用并發對象池

在本文中&#xff0c;我們將介紹如何在Java中創建對象池。 近年來&#xff0c;JVM的性能成倍增加&#xff0c;大多數類型的對象幾乎都變得多余&#xff0c;從而提高了對象池的性能。 從本質上講&#xff0c;對象的創建不再像以前那樣昂貴。 但是&#xff0c;有些對象在創建時肯…

圓周率的代碼表示,以及對其的理解。

轉載的簡書&#xff0c;for 記錄以及記憶。 http://www.jianshu.com/p/7208e4a58310 Thanks again&#xff01; 轉載于:https://www.cnblogs.com/xiapeng0701/p/7538281.html

華為NOVa8Pr0是用鴻蒙系統嗎,華為Nova8即將發布,采用麒麟芯片,高端平板適配鴻蒙系統...

大家好&#xff0c;我是老孫自從華為Mate40系列發布后&#xff0c;下一步新機動態備受外界關注&#xff0c;華為究竟會不會繼續生產手機呢&#xff1f;答案是肯定&#xff0c;華為Nova8系列將于本月發布&#xff0c;華為P50系列也在積極籌備&#xff0c;而且都少不了麒麟芯片&a…

使用路標的Scala和Java的Twitter REST API

如果您已閱讀此博客上的其他文章&#xff0c;您可能會知道我喜歡創建各種數據集的可視化。 我剛剛開始一個小項目&#xff0c;在這里我想可視化來自Twitter的一些數據。 為此&#xff0c;我想直接從Twitter檢索有關關注者的信息和個人資料信息。 我實際上開始尋找一組所有推特帳…

大話設計模式讀書筆記--11.抽象工廠模式

定義 抽象工廠模式定義: 提供一個創建一系列相關或相關依賴對象的接口,而無需指定他們具體的類 抽象工廠模式通常是用于創建一族產品&#xff0c;并且這族產品分不同的等級&#xff1b;不同的具體工廠類生產不同等級的一族產品 比如下圖(來源于網絡) 兩廂車和三廂車稱為兩個不同…