Thrift 是由 Facebook 開源的一個 RPC 框架,現在已經掛在 apache.org 下了。主要的幾個好處:
10年積累的網站建設、網站設計經驗,可以快速應對客戶對網站的新想法和需求。提供各種問題對應的解決方案。讓選擇我們的客戶得到更好、更有力的網絡服務。我雖然不認識你,你也不認識我。但先制作網站后付款的網站建設流程,更有措美免費網站建設讓你可以放心的選擇與我們合作。
1. 支持非常多語言,包括在 WEB 開發中很常用的 PHP,以及最重要的 C++/Python/Java 等 WEB后端常用語言,當然,還包括很 cool 的 Ruby、Erlang。
2. 完整的 RPC 框架實現,用腳本生成通訊相關的框架代碼,開發者只需要集中精力處理好 業務邏輯。比如搭建一個 Hello World Service 只需要幾分鐘。
3.擁有被 Facebook、Last.fm 等不少大規模互聯網應用驗證過的性能和可用性。
Hessian是一款基于HTTP協議的RPC框架,采用的是二進制RPC協議,非常輕量級 ,且速度較快。
當然,還有Hetty,它是一款構建于Netty和Hessian基礎上的高性能的RPC框架。
JSON-RPC-Java 由兩個對用戶可視化的組件構成,它們是JSONRPCBridge和JSONRPCServlet,二者的協調實現了JSON服務器端對請求對象的處理,并響應給用戶。
JSONRPCBridge是一個擁有服務器端導出給特定客戶端的對象的引用的session對象,它接收服務器(也就是JSONRPCServlet)傳來的JSON-RPC請求,然后其把JSON對象解碼(unmarshalling)為Java對象,再扮演方法調用的角色,還要把方法調用返回的Java對象結果組碼(marshall)為JSON對象傳給客戶端處理。而具體的從Java對象到Javascript對象的類型轉換由負責串行化的串行化類Serializer處理。
JSONRPCBridge必須放置在HttpSession對象中,并且注冊屬性名為“JSONRPCBridge”,以使JSONRPCServlet能夠定位負責調用導出到客戶端的Java對象的橋。為此,為了導出一個對象的所有實例和靜態方法到客戶端,應該有如下的代碼: JSONRPCBridge.registerObject("myObject", myObject);
為了導出一個類的所有的靜態方法,應該:JSONRPCBridge.registerClass(("myObject", myObject);
如果registerObject和registerClass被多次調用為有相同鍵值的對象使用,那么其將被最新賦值的對象所更新。
在JSON中,還可以使用單例模式的globalBridge來為所有的HTTP客戶端導出所有的實例方法。其可以用來注冊工廠類,但使用時要注意認證與安全問題。使用時如下標識:JSONRPCBridge.getGlobalBridge().registerObject("myObject",myObject); 同上其還可以導出所有的靜態方法。
該協議中最重要的一部分還有就是Servlet了,現在就來簡單的介紹一下:
在該協議中,JSONRPCServlet充當傳送器,處理通過HTTP傳輸過來的JSON
0,服務接口定義---Echo.java
/*
* 定義了服務器提供的服務類型 */public interface Echo { ? ?public String echo(String string);
}
一,客戶端代碼分析--實現類:MainClient.java
客戶端實現包括:獲得一個代理對象,并使用該代理對象調用服務器的服務。獲取代理對象時,需要指定被代理的類(相當于服務器端提供的服務名),Server IP,Port,這樣客戶端就能找到服務端的服務了。
延伸:分布式環境下,Client如何打到Server的服務?---因為,在服務器中運行的某些服務不像標準服務有著固定的端口,如HTTP的80端口。
一種解決方法是:在運行服務的每臺機器上都運行一個特殊的守護進程,該守護進程負責跟蹤位于該機器中每一項服務所使用的端口;此外,守護進程還監聽一個特定的已經端口,Client通過這個端口與守護進程聯系,請求得到指定服務的端口。
復雜的RPC實現框架中,比如可以把服務注冊到ZooKeeper中,Client也從ZooKeeper中查詢服務。參考:一個更復雜的RPC框架實現
Echo echo = RPC.getProxy(Echo.class, "127.0.0.1", 20382);
System.out.println(echo.echo("hello,hello"));//使用代理對象調用服務器的服務.并將結果輸出
二,服務器端分析--實現類:MainServer.java
服務器實現包括:創建一個服務器對象,將它能提供的服務注冊,并啟動進程監聽客戶端的連接
Server server = new RPC.RPCServer(); ? ? ? ?/*
* server 啟動后,需要注冊server端能夠提供的服務,這樣client使用 服務的名字、
* 服務器的IP、以及服務所運行的端口 來調用 server 的服務 ? ? ? ? */
server.register(Echo.class, RemoteEcho.class);//注冊服務的名字
server.register(AnOtherEchoService.class, AnOtherEchoServiceImpl.class);
server.start();//啟動server
三,服務器監聽Client連接分析----實現類:Listener.java
當server.start()后,它要創建一個Listener對象,這是一個線程類,該線程用來監聽Client連接。
public void start() {
System.out.println("啟動服務器");
/*
* server 啟動時,需要Listener監聽是否有client的請求連接
* listener 是一個線程,由它來監聽連接 ? ? ? ? ? ? */
listener = new Listener(this); ? ? ? ? ? ?this.isRuning = true;
listener.start();//listener 是一個線程類,start()后會執行線程的run方法
}
其實,監聽連接就是JAVA ServerSocket類和Socket類提供的相關功能而已。
/*
* accept()是一個阻塞方法,server_socket 一直等待client 是否有連接到來 */
Socket client = server_socket.accept();//建立一條TCP連接
四,動態代理對象 生成---RPC.java
客戶端只需要編寫生成代理對象,用代理對象去調用遠程服務的代碼即可。但是,底層的功能如:建立連接,序列化(本例中也沒有考慮),跨語言調用(未考慮)...是由RPC框架完成的。
當MainClient 語句:RPC.getProxy(Echo.class, "127.0.0.1", 20382);執行時,會由
/*
* @param Class[]{} 該參數聲明了動態生成的代理對象實現了的接口,即 clazz 所代表的接口類型 .
* 這表明了生成的代理對象它是一個它所實現了的接口類型的對象
* 從而就可以用它來調用它所實現的接口中定義的方法
*
* @param handler 生成代理實例對象時需要傳遞一個handler參數
* 這樣當該 代理實例對象調用接口中定義的方法時,將會委托給InvocationHandler 接口中聲明的invoke方法
* 此時,InvocationHandler 的invoke 方法將會被自動調用 ? ? ? ? */
T t = (T) Proxy.newProxyInstance(RPC.class.getClassLoader(), new Class[] {clazz}, handler); ? ? ? ?return t;
返回該代理對象,然后就會委托第三個參數 handler 自動執行 invoke(),invoke將客戶端調用的所有相關信息封裝到Invocation 對象中(后面分析)。然后執行第16行代碼發起連接。
1 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { 2 ? ? ? ? ? ? ? ? Invocation invo = new Invocation(); 3 ?? ? ? ? ? ? ? ?invo.setInterfaces(clazz); 4 ? ? ? ? ? ? ? ? ?5 ? ? ? ? ? ? ? ? //利用反射機制將java.lang.reflect.Method 所代表的方法名,參數 封裝到 Invocation invo對象中 6 ? ? ? ? ? ? ? ? invo.setMethod(new org.jy.rpc.protocal.Method(method.getName(),method.getParameterTypes())); 7 ?? ? ? ? ? ? ? ?invo.setParams(args); 8 ? ? ? ? ? ? ? ? ?9 ? ? ? ? ? ? ? ? /*10 ?? ? ? ? ? ? ? ? * 當把需要調用的遠程server端的方法名和參數封裝到invo之后,Client 對象 就可以把 invo 作為參數 傳遞給服務器了.11 ?? ? ? ? ? ? ? ? * 為什么需要這樣做呢?InvocationHandler 的invoke方法是自動執行的,在該方法里面,它根據生成的代理對象 proxy (第一個參數)12 ?? ? ? ? ? ? ? ? * 所實現的接口(由 Proxy.newProxyInstance()的第二個參數指定) 就可以知道這個接口中定義了哪些方法13 ?? ? ? ? ? ? ? ? * InvocationHandler 的 invoke 方法的第二個參數Method method 就可以解析出接口中的方法名和參數了14 ?? ? ? ? ? ? ? ? * 把它們封裝進Invocation invo對象中,再將 invo 作為 client.invoke(invo)的參數 發送到服務器方15 ? ? ? ? ? ? ? ? ?*/16 ? ? ? ? ? ? ? ? client.invoke(invo);//invoke 先調用init發起一個Socket連接,再將invo 發送至輸出流中17 ? ? ? ? ? ? ? ? return invo.getResult();18 ? ? ? ? ? ? }
五,“客戶端存根”--Client.java
最重要的是它的 invoke方法(注意與InvocationHandler的invoke()區分)。它負責建立連接,打開輸入、輸出流,向服務器發送字節數據。
1 ? ? public void invoke(Invocation invo) throws UnknownHostException, IOException, ClassNotFoundException {2 ?? ? ? ?init();3 ? ? ? ? System.out.println("寫入數據");4 ? ? ? ? oos.writeObject(invo);//將Client 需要調用的Server的 接口、方法、參數 封裝起來 發給服務器5 ?? ? ? ?oos.flush();6 ? ? ? ? ois = new ObjectInputStream(socket.getInputStream());//用來接收從 server 返回 回來的執行結果 的輸入流7 ? ? ? ? Invocation result = (Invocation) ois.readObject();8 ? ? ? ? invo.setResult(result.getResult());//將結果 保存到 Invocation result對象中9 ? ? }
六,“服務器存根“---實現類:RPCServer.java
上面提到,服務器通過Listener監聽客戶端連接,當建立客戶端連接后,Socket client = server_socket.accept(); 不再阻塞,服務器調用它的call()方法完成客戶端請求的功能。也即,客戶端請求的結果實際上是在服務器執行生成的。返回的結果是在Client.java 的 invoke() 方法里被讀取出來 。call()再一次用到了JAVA反射(第11行) 參考:JAVA動態代理
1 public void call(Invocation invo) { 2 ?? ? ? ? ? ?System.out.println(invo.getClass().getName()); 3 ? ? ? ? ? ? Object obj = serviceEngine.get(invo.getInterfaces().getName()); 4 ? ? ? ? ? ? if(obj!=null) { 5 ? ? ? ? ? ? ? ? try { 6 ? ? ? ? ? ? ? ? ? ? Method m = obj.getClass().getMethod(invo.getMethod().getMethodName(), invo.getMethod().getParams()); 7 ? ? ? ? ? ? ? ? ? ? /* 8 ?? ? ? ? ? ? ? ? ? ? * 利用JAVA反射機制來執行java.lang.reflect.Method 所代表的方法 9 ?? ? ? ? ? ? ? ? ? ? * @param result : 執行實際方法后 得到的 服務的執行結果10 ? ? ? ? ? ? ? ? ? ? ?*/11 ? ? ? ? ? ? ? ? ? ? Object result = m.invoke(obj, invo.getParams());12 ? ? ? ? ? ? ? ? ? ? invo.setResult(result);//將服務的執行結果封裝到invo對象中。在后面的代碼中,將該對象寫入到輸出流中13 ? ? ? ? ? ? ? ? } catch (Throwable th) {14 ?? ? ? ? ? ? ? ? ? ?th.printStackTrace();15 ?? ? ? ? ? ? ? ?}16 ? ? ? ? ? ? } else {17 ? ? ? ? ? ? ? ? throw new IllegalArgumentException("has no these class");18 ?? ? ? ? ? ?}19 ? ? ? ? }
七,”RPC 編碼、解碼,協議的定義“---Invocation.java?? Method.java
其實,這里并不是那種實用的開源RPC框架如Thrift中所指的編碼、IDL……上面兩個類只是RPC實現過程中輔助完成Java動態代理的實現,說白了就是封裝客戶端需要調用的方法,然后指定生成的代理對象需要實現的接口(服務).
八,總結:
先運行MainServer.java啟動服務器,然后,再運行MainClient.java 啟動一個客戶端連接服務器就可以看到執行結果。
當需要添加新的服務時:按以下步驟即可:①定義服務接口及其實現類,如:AnOtherEchoService.java? ②:在MainServer.java中注冊新添加的服務。
③:在MainClient.java中編寫獲得新服務的代理對象的代碼,并用該代理對象調用新服務接口中聲明的方法。
這樣,在客戶端就能夠遠程地調用服務器上的一個新服務了。
HTTP/1.1 協議規定的 HTTP 請求方法有 OPTIONS、GET、HEAD、POST、PUT、DELETE、TRACE、CONNECT 這幾種。其中,POST 一般用來向服務端提交數據,本文主要討論 POST 提交數據的幾種方式。
我們知道,HTTP 協議是以 ASCII 碼傳輸,建立在 TCP/IP 協議之上的應用層規范。規范把 HTTP 請求分為三個部分:狀態行、請求頭、消息主體。類似于下面形式:
method request-URL version headers entity-body
協議規定,POST 提交的數據必須放在消息主體(entity-body)中,但協議并沒有規定數據必須使用什么編碼方式。實際上,開發者完全可以自己決定消息主體的格式,只要最后發送的 HTTP 請求滿足上面的格式就可以。
1.,選擇其中的win版本下載,我選擇的是protoc-2.4.1-win32.zip
2.下載一個protobuf-java-2.4.1.jar文件(注意,要與你剛才下的proto.exe版本相同)
然后就開始開發了。
步驟:
1.用記事本編寫一個.proto文件:
}如:編寫的是test.proto
package protobuf;
option java_package = "com.sq.protobuf";
option java_outer_classname = "FirstProtobuf";
message testBuf {
required int32 ID = 1;
required string Url = 2;
}
將其放在與剛解壓的protoc.exe同級目錄中。
2.在cmd中,到protoc-2.4.1-win32文件夾下,
執行
E:\protoc-2.4.1-win32 protoc.exe --java_out=./ test.proto
則可以找到的一個生成的FirstProtobuf.java文件。
3.在MyEclipse中新建一個java project,建立包com.sq.protobuf,然后將剛才生成的FirstProtobuf.java文件放在其下面。
此時會報錯,因為沒有引入jar包,在package視圖下,將protobuf-java-2.4.1.jar引入,即可解決問題。
java調用wsdl的步驟如下,主要是使用第三方框架:
步驟如下:
1.下載AXIS2類庫,AXIS2是目前java調用webservice的一個主要方法(由于更新較頻繁,請自行google該類庫的網址)
2.由于是第三方webservice,直接引入AXIS2的包就可以用了,代碼如下:
import?java.rmi.RemoteException;
import?javax.xml.rpc.ParameterMode;
import?javax.xml.rpc.ServiceException;
import?org.apache.axis.client.Call;
import?org.apache.axis.client.Service;
import?org.apache.axis.encoding.XMLType;
public?class?webServiceTest?{
public?String?invokeRemoteFuc()?{
String?endpoint?=?"";
String?result?=?"no?result!";
Service?service?=?new?Service();
Call?call;
Object[]?object?=?new?Object[1];
object[0]?=?"Dear?I?miss?you";//Object是用來存儲方法的參數
try?{
call?=?(Call)?service.createCall();
call.setTargetEndpointAddress(endpoint);//?遠程調用路徑
call.setOperationName("say");//?調用的方法名
//?設置參數名:
call.addParameter("str1",?//?參數名
XMLType.XSD_STRING,//?參數類型:String
ParameterMode.IN);//?參數模式:'IN'?or?'OUT'
//?設置返回值類型:
call.setReturnType(XMLType.XSD_STRING);//?返回值類型:String?????????
result?=?(String)?call.invoke(object);//?遠程調用
}?catch?(ServiceException?e)?{
e.printStackTrace();
}?catch?(RemoteException?e)?{
e.printStackTrace();
}
return?result;
}
public?static?void?main(String[]?args)?{
webServiceTest?t?=?new?webServiceTest();
String?result?=?t.invokeRemoteFuc();
System.out.println(result);
}
}
該方法的原理很簡單,通過AXIS2封裝好的類設置URL和參數,直接調用就好了,我們要關注的就是設置URL,方法,還有方法的參數,其他的copypaste好啦,很簡單吧,再看看其他的方法,我勒個去了,害我瞎搞兩天。遲點上個源碼共大家參考!
新聞標題:javarpc代碼,javarpc原理
本文網址:http://vcdvsql.cn/article16/hedogg.html
成都網站建設公司_創新互聯,為您提供Google、品牌網站設計、全網營銷推廣、做網站、網站內鏈、品牌網站建設
聲明:本網站發布的內容(圖片、視頻和文字)以用戶投稿、用戶轉載內容為主,如果涉及侵權請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網站立場,如需處理請聯系客服。電話:028-86922220;郵箱:631063699@qq.com。內容未經允許不得轉載,或轉載時需注明來源: 創新互聯