远程过程调用RPC RMI(Remote Method Invocation)和Web Service

一、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();
	}

	@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接口拷贝过来,并且必须和服务器端包名相同。否则会报如下错误(本人亲测):

        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();   
	        } 
	    } 
}

服务端工程结构截图 

175150_cgdF_579493.png

客户端工程结构截图

175317_5rpV_579493.png

先运行服务器端代码,在运行客户端代码。运行结果:

175609_lVvQ_579493.png

三、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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值