遠程過程調用RPC RMI(Remote Method Invocation)和Web Service

1、RPC是什麼

    RPC的全稱是Remote Procedure call,是進程間通訊方式。java

    他容許程序調用另外一個地址空間的過程或者函數,不用去關注此過程或函數的實現細節。好比兩臺服務器A,B,一個應用部署在A服務器上,想要調用B服務器上應用提供的函數或者方法,因爲不在一個內存空間,不能直接調用,這時候須要經過就能夠應用RPC框架的實現來解決。web

2、RPC的實現

    RPC有不少開源的框架實現這裏主要介紹java自帶的RMI編程

    一、RMI是什麼

        RMI全稱是Remote Method Invocation-遠程方法調用,Java RMI在JDK1.1中實現的,其威力就體如今它強大的開發分佈式網絡應用的能力上,是純Java的網絡分佈式應用系統的核心解決方案之一。其實它能夠被看做是RPC的Java版本。要求客戶端和服務端都要用java實現服務器

    二、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接口拷貝過來,而且必須和服務器端包名相同。不然會報以下錯誤(本人親測):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();   
	        } 
	    } 
}

服務端工程結構截圖 

客戶端工程結構截圖

先運行服務器端代碼,在運行客戶端代碼。運行結果:

3、Web Service

    一、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文件咱們就能夠進行編程。

相關文章
相關標籤/搜索