远程过程调用RPC RMI(Remote Method Invocation)和Web Service
2019獨(dú)角獸企業(yè)重金招聘Python工程師標(biāo)準(zhǔn)>>>
一、RPC是什么
? ? RPC的全稱是Remote Procedure call,是進(jìn)程間通信方式。
? ? 他允許程序調(diào)用另一個(gè)地址空間的過(guò)程或者函數(shù),不用去關(guān)注此過(guò)程或函數(shù)的實(shí)現(xiàn)細(xì)節(jié)。比如兩臺(tái)服務(wù)器A,B,一個(gè)應(yīng)用部署在A服務(wù)器上,想要調(diào)用B服務(wù)器上應(yīng)用提供的函數(shù)或者方法,由于不在一個(gè)內(nèi)存空間,不能直接調(diào)用,這時(shí)候需要通過(guò)就可以應(yīng)用RPC框架的實(shí)現(xiàn)來(lái)解決。
二、RPC的實(shí)現(xiàn)
? ? RPC有很多開(kāi)源的框架實(shí)現(xiàn)這里主要介紹java自帶的RMI
? ? 1、RMI是什么
????????RMI全稱是Remote?Method?Invocation-遠(yuǎn)程方法調(diào)用,Java?RMI在JDK1.1中實(shí)現(xiàn)的,其威力就體現(xiàn)在它強(qiáng)大的開(kāi)發(fā)分布式網(wǎng)絡(luò)應(yīng)用的能力上,是純Java的網(wǎng)絡(luò)分布式應(yīng)用系統(tǒng)的核心解決方案之一。其實(shí)它可以被看作是RPC的Java版本。要求客戶端和服務(wù)端都要用java實(shí)現(xiàn)
? ? 2、RMI簡(jiǎn)單實(shí)例
? ? (1)服務(wù)端代碼實(shí)現(xiàn):
????IHello類實(shí)現(xiàn):
import java.rmi.Remote; import java.rmi.RemoteException;public interface IHello extends Remote{/** * 簡(jiǎn)單的返回“Hello World!"字樣 * @return 返回“Hello World!"字樣 * @throws java.rmi.RemoteException */ public String helloWorld() throws RemoteException; /** * 一個(gè)簡(jiǎn)單的業(yè)務(wù)方法,根據(jù)傳入的人名返回相應(yīng)的問(wèn)候語(yǔ) * @param someBodyName 人名 * @return 返回相應(yīng)的問(wèn)候語(yǔ) * @throws java.rmi.RemoteException */ public String sayHelloToSomeBody(String someBodyName) throws RemoteException; }? ? HelloImpl實(shí)現(xiàn)IHello實(shí)現(xiàn):
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 * 創(chuàng)建RMI注冊(cè)表,啟動(dòng)RMI服務(wù),并將遠(yuǎn)程對(duì)象注冊(cè)到RMI注冊(cè)表中。 */ public class HelloServer { public static void main(String args[]) throws java.rmi.AlreadyBoundException { try { //創(chuàng)建一個(gè)遠(yuǎn)程對(duì)象 IHello rhello = new HelloImpl(); //本地主機(jī)上的遠(yuǎn)程對(duì)象注冊(cè)表Registry的實(shí)例,并指定端口為8888,這一步必不可少(Java默認(rèn)端口是1099),必不可缺的一步,缺少注冊(cè)表創(chuàng)建,則無(wú)法綁定對(duì)象到遠(yuǎn)程注冊(cè)表上 LocateRegistry.createRegistry(8888); //把遠(yuǎn)程對(duì)象注冊(cè)到RMI注冊(cè)服務(wù)器上,并命名為RHello //綁定的URL標(biāo)準(zhǔn)格式為:rmi://host:port/name(其中協(xié)議名可以省略,下面兩種寫法都是正確的) Naming.bind("rmi://localhost:8888/RHello",rhello); // Naming.bind("//localhost:8888/RHello",rhello); System.out.println(">>>>>INFO:遠(yuǎn)程IHello對(duì)象綁定成功!"); } catch (RemoteException e) { System.out.println("創(chuàng)建遠(yuǎn)程對(duì)象發(fā)生異常!"); e.printStackTrace(); } catch (AlreadyBoundException e) { System.out.println("發(fā)生重復(fù)綁定對(duì)象異常!"); e.printStackTrace(); } catch (MalformedURLException e) { System.out.println("發(fā)生URL畸形異常!"); e.printStackTrace(); } } }? ?(2)客戶端代碼實(shí)現(xiàn):
???? 新建客戶端工程GiveMeWords,客戶端需要將服務(wù)端的IHello接口拷貝過(guò)來(lái),并且必須和服務(wù)器端包名相同。否則會(huì)報(bào)如下錯(cuò)誤(本人親測(cè)):
????????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服務(wù)注冊(cè)表中查找名稱為RHello的對(duì)象,并調(diào)用其上的方法 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(); } } }服務(wù)端工程結(jié)構(gòu)截圖?
客戶端工程結(jié)構(gòu)截圖
先運(yùn)行服務(wù)器端代碼,在運(yùn)行客戶端代碼。運(yùn)行結(jié)果:
三、Web Service
? ? 1、WebService是一種跨編程語(yǔ)言和跨操作系統(tǒng)平臺(tái)的遠(yuǎn)程調(diào)用技術(shù)。
? ? ????XML+XSD,SOAP和WSDL就是構(gòu)成WebService平臺(tái)的三大技術(shù)。Web Service采用http協(xié)議傳輸,數(shù)據(jù)格式為特定格式的XML。
????? ? SOAP協(xié)議=HTTP協(xié)議+XML協(xié)議
????????WSDL(Web Service Description Language)基于XML語(yǔ)音的,用于描述Web Service及其函數(shù)、參數(shù)和返回值。它是WebService客戶端和服務(wù)器端都能理解的標(biāo)準(zhǔn)格式。WSDL文件保存在Web服務(wù)器上,通過(guò)一個(gè)url地址就可以訪問(wèn)到它。客戶端要調(diào)用一個(gè)WebService服務(wù)之前,要知道該服務(wù)的WSDL文件的地址。WebService服務(wù)提供商可以通過(guò)兩種方式來(lái)暴露它的WSDL文件地址:1.注冊(cè)到UDDI服務(wù)器,以便被人查找;2.直接告訴給客戶端調(diào)用者。也就是說(shuō)我們要進(jìn)行Web Service開(kāi)發(fā),通過(guò)服務(wù)器端的WSDL文件,我們就可以編寫客戶端調(diào)用代碼。
????? ? 服務(wù)端代碼:
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");} }運(yùn)行成功后訪問(wèn)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服務(wù)的定義中使用下列元素:
- Types?- 數(shù)據(jù)類型定義的容器,它使用某種類型系統(tǒng)(一般地使用XML Schema中的類型系統(tǒng))。
- Message?- 通信消息的數(shù)據(jù)結(jié)構(gòu)的抽象類型化定義。使用Types所定義的類型來(lái)定義整個(gè)消息的數(shù)據(jù)結(jié)構(gòu)。
- Operation?- 對(duì)服務(wù)中所支持的操作的抽象描述,一般單個(gè)Operation描述了一個(gè)訪問(wèn)入口的請(qǐng)求/響應(yīng)消息對(duì)。
- PortType?- 對(duì)于某個(gè)訪問(wèn)入口點(diǎn)類型所支持的操作的抽象集合,這些操作可以由一個(gè)或多個(gè)服務(wù)訪問(wèn)點(diǎn)來(lái)支持。
- Binding?- 特定端口類型的具體協(xié)議和數(shù)據(jù)格式規(guī)范的綁定。
- Port?- 定義為協(xié)議/數(shù)據(jù)格式綁定與具體Web訪問(wèn)地址組合的單個(gè)服務(wù)訪問(wèn)點(diǎn)。
- Service- 相關(guān)服務(wù)訪問(wèn)點(diǎn)的集合。
? ? 然后在客戶端項(xiàng)目下運(yùn)行如下命令?wsimport -s Documents/workspace/GiveMeWords/src?-p com.shu.service?-keep http://localhost:9001/Service/Function?wsdl?即可自動(dòng)生成客戶端代碼
????Documents/workspace/GiveMeWords/src代碼位置
????com.shu.service包名
? ? 測(cè)試代碼:
public class Test {/*** 測(cè)試webservice此作為客戶端* test項(xiàng)目中的webService包下面的Function作為服務(wù)端*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);} }? ? 運(yùn)行即可調(diào)用服務(wù)端的遠(yuǎn)程方法transWords()方法。但是客戶端怎么知道服務(wù)端暴露出來(lái)的服務(wù)就是transWords呢,還有參數(shù)返回值這些客戶端是怎么知道的?我們回到上面的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表情表明方法暴露服務(wù)的方法名是transWords。<input>標(biāo)簽標(biāo)示輸入?yún)?shù),<output>函數(shù)返回值。這樣我們就得到了我們想要的接口了。總之通過(guò)WSDL文件我們就可以進(jìn)行編程。
轉(zhuǎn)載于:https://my.oschina.net/u/579493/blog/897359
總結(jié)
以上是生活随笔為你收集整理的远程过程调用RPC RMI(Remote Method Invocation)和Web Service的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 启动流程和系统管理
- 下一篇: 《深入实践Spring Boot》一3.