RPC的全称是Remote Procedure call,是进程间通讯方式。java
他容许程序调用另外一个地址空间的过程或者函数,不用去关注此过程或函数的实现细节。好比两台服务器A,B,一个应用部署在A服务器上,想要调用B服务器上应用提供的函数或者方法,因为不在一个内存空间,不能直接调用,这时候须要经过就能够应用RPC框架的实现来解决。web
RPC有不少开源的框架实现这里主要介绍java自带的RMI编程
RMI全称是Remote Method Invocation-远程方法调用,Java RMI在JDK1.1中实现的,其威力就体如今它强大的开发分布式网络应用的能力上,是纯Java的网络分布式应用系统的核心解决方案之一。其实它能够被看做是RPC的Java版本。要求客户端和服务端都要用java实现服务器
(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(); } @Override public String helloWorld() throws RemoteException { return "Hello Word"; } @Override public 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接口拷贝过来,而且必须和服务器端包名相同。不然会报以下错误(本人亲测):ide
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(); } } }
服务端工程结构截图
客户端工程结构截图
先运行服务器端代码,在运行客户端代码。运行结果:
一、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服务的定义中使用下列元素:
而后在客户端项目下运行以下命令 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文件咱们就能够进行编程。