远程过程调用RPC RMI(Remote Method Invocation)和Web Service
2019獨角獸企業重金招聘Python工程師標準>>>
一、RPC是什么
? ? RPC的全稱是Remote Procedure call,是進程間通信方式。
? ? 他允許程序調用另一個地址空間的過程或者函數,不用去關注此過程或函數的實現細節。比如兩臺服務器A,B,一個應用部署在A服務器上,想要調用B服務器上應用提供的函數或者方法,由于不在一個內存空間,不能直接調用,這時候需要通過就可以應用RPC框架的實現來解決。
二、RPC的實現
? ? RPC有很多開源的框架實現這里主要介紹java自帶的RMI
? ? 1、RMI是什么
????????RMI全稱是Remote?Method?Invocation-遠程方法調用,Java?RMI在JDK1.1中實現的,其威力就體現在它強大的開發分布式網絡應用的能力上,是純Java的網絡分布式應用系統的核心解決方案之一。其實它可以被看作是RPC的Java版本。要求客戶端和服務端都要用java實現
? ? 2、RMI簡單實例
? ? (1)服務端代碼實現:
????IHello類實現:
import java.rmi.Remote; import java.rmi.RemoteException;public interface IHello extends Remote{/** * 簡單的返回“Hello World!"字樣 * @return 返回“Hello World!"字樣 * @throws java.rmi.RemoteException */ public String helloWorld() throws RemoteException; /** * 一個簡單的業務方法,根據傳入的人名返回相應的問候語 * @param someBodyName 人名 * @return 返回相應的問候語 * @throws java.rmi.RemoteException */ public String sayHelloToSomeBody(String someBodyName) throws RemoteException; }? ? HelloImpl實現IHello實現:
import java.rmi.RemoteException; import java.rmi.server.UnicastRemoteObject;public class HelloImpl extends UnicastRemoteObject implements IHello{protected HelloImpl() throws RemoteException {super();}@Overridepublic String helloWorld() throws RemoteException {return "Hello Word";}@Overridepublic String sayHelloToSomeBody(String someBodyName) throws RemoteException {return "你好," + someBodyName + "!";}}? ? HelloServer:
import java.net.MalformedURLException; import java.nio.channels.AlreadyBoundException; import java.rmi.Naming; import java.rmi.RemoteException; import java.rmi.registry.LocateRegistry;/** * Created by IntelliJ IDEA. * Date: 2008-8-7 22:03:35 * 創建RMI注冊表,啟動RMI服務,并將遠程對象注冊到RMI注冊表中。 */ public class HelloServer { public static void main(String args[]) throws java.rmi.AlreadyBoundException { try { //創建一個遠程對象 IHello rhello = new HelloImpl(); //本地主機上的遠程對象注冊表Registry的實例,并指定端口為8888,這一步必不可少(Java默認端口是1099),必不可缺的一步,缺少注冊表創建,則無法綁定對象到遠程注冊表上 LocateRegistry.createRegistry(8888); //把遠程對象注冊到RMI注冊服務器上,并命名為RHello //綁定的URL標準格式為:rmi://host:port/name(其中協議名可以省略,下面兩種寫法都是正確的) Naming.bind("rmi://localhost:8888/RHello",rhello); // Naming.bind("//localhost:8888/RHello",rhello); System.out.println(">>>>>INFO:遠程IHello對象綁定成功!"); } catch (RemoteException e) { System.out.println("創建遠程對象發生異常!"); e.printStackTrace(); } catch (AlreadyBoundException e) { System.out.println("發生重復綁定對象異常!"); e.printStackTrace(); } catch (MalformedURLException e) { System.out.println("發生URL畸形異常!"); e.printStackTrace(); } } }? ?(2)客戶端代碼實現:
???? 新建客戶端工程GiveMeWords,客戶端需要將服務端的IHello接口拷貝過來,并且必須和服務器端包名相同。否則會報如下錯誤(本人親測):
????????java.lang.ClassNotFoundException: test.rmi.IHello (no security manager: RMI class loader)
import java.net.MalformedURLException; import java.rmi.Naming; import java.rmi.NotBoundException; import java.rmi.RemoteException;public class HelloClient {public static void main(String args[]){ try { //在RMI服務注冊表中查找名稱為RHello的對象,并調用其上的方法 IHello rhello =(IHello) Naming.lookup("rmi://localhost:8888/RHello"); System.out.println(rhello.helloWorld()); System.out.println(rhello.sayHelloToSomeBody("熔巖")); } catch (NotBoundException e) { e.printStackTrace(); } catch (MalformedURLException e) { e.printStackTrace(); } catch (RemoteException e) { e.printStackTrace(); } } }服務端工程結構截圖?
客戶端工程結構截圖
先運行服務器端代碼,在運行客戶端代碼。運行結果:
三、Web Service
? ? 1、WebService是一種跨編程語言和跨操作系統平臺的遠程調用技術。
? ? ????XML+XSD,SOAP和WSDL就是構成WebService平臺的三大技術。Web Service采用http協議傳輸,數據格式為特定格式的XML。
????? ? SOAP協議=HTTP協議+XML協議
????????WSDL(Web Service Description Language)基于XML語音的,用于描述Web Service及其函數、參數和返回值。它是WebService客戶端和服務器端都能理解的標準格式。WSDL文件保存在Web服務器上,通過一個url地址就可以訪問到它??蛻舳艘{用一個WebService服務之前,要知道該服務的WSDL文件的地址。WebService服務提供商可以通過兩種方式來暴露它的WSDL文件地址:1.注冊到UDDI服務器,以便被人查找;2.直接告訴給客戶端調用者。也就是說我們要進行Web Service開發,通過服務器端的WSDL文件,我們就可以編寫客戶端調用代碼。
????? ? 服務端代碼:
import javax.jws.WebService; import javax.xml.ws.Endpoint;@WebService public class Function {public String transWords(String words){String res = "";for(char ch : words.toCharArray()){res += "\t" + ch + "\t";}return res;}public static void main(String[] args){Endpoint.publish("http://localhost:9001/Service/Function", new Function());System.out.println("publish success");} }運行成功后訪問http://localhost:9001/Service/Function?wsdl。wsdl文件如下:
<!--Published by JAX-WS RI at http://jax-ws.dev.java.net. RI's version is JAX-WS RI 2.2.4-b01. --> <!--Generated by JAX-WS RI at http://jax-ws.dev.java.net. RI's version is JAX-WS RI 2.2.4-b01. --> <definitions xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" xmlns:wsp="http://www.w3.org/ns/ws-policy" xmlns:wsp1_2="http://schemas.xmlsoap.org/ws/2004/09/policy" xmlns:wsam="http://www.w3.org/2007/05/addressing/metadata" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:tns="http://webService.test/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://schemas.xmlsoap.org/wsdl/" targetNamespace="http://webService.test/" name="FunctionService"> <types> <xsd:schema> <xsd:import namespace="http://webService.test/" schemaLocation="http://localhost:9001/Service/Function?xsd=1"/> </xsd:schema> </types> <message name="transWords"> <part name="parameters" element="tns:transWords"/> </message> <message name="transWordsResponse"> <part name="parameters" element="tns:transWordsResponse"/> </message> <portType name="Function"> <operation name="transWords"> <input wsam:Action="http://webService.test/Function/transWordsRequest" message="tns:transWords"/> <output wsam:Action="http://webService.test/Function/transWordsResponse" message="tns:transWordsResponse"/> </operation> </portType> <binding name="FunctionPortBinding" type="tns:Function"> <soap:binding transport="http://schemas.xmlsoap.org/soap/http" style="document"/> <operation name="transWords"> <soap:operation soapAction=""/> <input> <soap:body use="literal"/> </input> <output> <soap:body use="literal"/> </output> </operation> </binding> <service name="FunctionService"> <port name="FunctionPort" binding="tns:FunctionPortBinding"> <soap:address location="http://localhost:9001/Service/Function"/> </port> </service> </definitions>? ??WSDL 文檔在Web服務的定義中使用下列元素:
- Types?- 數據類型定義的容器,它使用某種類型系統(一般地使用XML Schema中的類型系統)。
- Message?- 通信消息的數據結構的抽象類型化定義。使用Types所定義的類型來定義整個消息的數據結構。
- Operation?- 對服務中所支持的操作的抽象描述,一般單個Operation描述了一個訪問入口的請求/響應消息對。
- PortType?- 對于某個訪問入口點類型所支持的操作的抽象集合,這些操作可以由一個或多個服務訪問點來支持。
- Binding?- 特定端口類型的具體協議和數據格式規范的綁定。
- Port?- 定義為協議/數據格式綁定與具體Web訪問地址組合的單個服務訪問點。
- Service- 相關服務訪問點的集合。
? ? 然后在客戶端項目下運行如下命令?wsimport -s Documents/workspace/GiveMeWords/src?-p com.shu.service?-keep http://localhost:9001/Service/Function?wsdl?即可自動生成客戶端代碼
????Documents/workspace/GiveMeWords/src代碼位置
????com.shu.service包名
? ? 測試代碼:
public class Test {/*** 測試webservice此作為客戶端* test項目中的webService包下面的Function作為服務端*wsimport -s Documents/workspace/GiveMeWords/src -p com.shu.service -keep http://localhost:9001/Service/Function?wsdl* @param args*/public static void main(String[] args){Function fu = new FunctionService().getFunctionPort();String str = fu.transWords("get my words");System.out.println(str);} }? ? 運行即可調用服務端的遠程方法transWords()方法。但是客戶端怎么知道服務端暴露出來的服務就是transWords呢,還有參數返回值這些客戶端是怎么知道的?我們回到上面的WSDL文件:
<portType name="Function"> <operation name="transWords"> <input wsam:Action="http://webService.test/Function/transWordsRequest" message="tns:transWords"/> <output wsam:Action="http://webService.test/Function/transWordsResponse" message="tns:transWordsResponse"/> </operation> </portType>operation表情表明方法暴露服務的方法名是transWords。<input>標簽標示輸入參數,<output>函數返回值。這樣我們就得到了我們想要的接口了??傊ㄟ^WSDL文件我們就可以進行編程。
轉載于:https://my.oschina.net/u/579493/blog/897359
總結
以上是生活随笔為你收集整理的远程过程调用RPC RMI(Remote Method Invocation)和Web Service的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 启动流程和系统管理
- 下一篇: 记一次培训机构“面试”过程