什麼是RPC? RPC是Remote Procedure Call的縮寫,像Client-Servier同樣的遠程過程調用,也就是調用遠程服務就跟調用本地服務同樣方便,通常用於將程序部署在不一樣的機器上,供客戶端進行調用。就像一個request-response調用系統同樣簡單。在面向對象編程的程序中,RPC也能夠用Remote method invocation(RMI)來展示。爲何用它呢,由於隨着分佈式結構的廣泛,愈來愈多的應用須要解耦,將不一樣的獨立功能部署發佈成不一樣的服務供調用。java
它的主要流程是Client -> Client Stub -> Network -> Server Stub -> Server 執行完成以後再進行返回。web
這裏邊比較重要的就是Clint Stub和Server Stub,他們主要的做用就是將調用的方法和參數進行編碼(Marshalling)序列化,將序列化後的數據經過網絡發送給Server Stub,而後等待Server回執。Server Stub將受到的序列化字節進行解碼(Unmarshaling)反序列化,而後再將參數傳入到對應到的方法中執行,將得出的結果計算出來以後再進行返回,返回的過程和正向的過程相似。編程
那麼這個結構裏邊的內容這麼複雜,並且還須要保證數據的完整,網絡等因素,因此這塊有一個通信的標準就是IDL(Interface Description Language)接口定義語言,由於不少程序採用了不一樣的編程語言(Java,C, C++ etc.)和不一樣的操做系統(Windows, CentOs, RHEL etc.),要保證數據可以正常通信,而且不受語言和操做系統等限制,就有了它。好比Apache的Thrift 、Avro和Google的 Protocol Buffers、阿里的Dubbo等。小程序
其實不少人早已經應用了它了,可是可能不知道,好比web service的WSDL。下面我就用一個小程序來建立一個簡單基於的WSDL的RPC。使用JDK的JAX-WS實現網絡
接口類(定義了一個很是簡單的方法):編程語言
package com.hqs.rpc; import javax.jws.WebMethod; import javax.jws.WebService; import javax.jws.soap.SOAPBinding; import javax.jws.soap.SOAPBinding.Style; /** * 接口 * @author hqs * */ @WebService @SOAPBinding(style = Style.RPC) public interface IRPCService { @WebMethod public String RPCMethod(String str); }
實現類:分佈式
package com.hqs.rpc; import javax.jws.WebService; /** * 實現類 * @author hqs * */ @WebService (endpointInterface = "com.hqs.rpc.IRPCService") public class RPCServiceImpl implements IRPCService { @Override public String RPCMethod(String str) { System.out.println("service received:" + str); return "RPC Method invoked: " + str; } }
服務發佈類:ide
package com.hqs.rpc; import javax.xml.ws.Endpoint; /** * 發佈類 * @author hqs * */ public class RPCPublisher { public static void main(String[] args) { //本身定義地址 Endpoint.publish("http://localhost:9966/rpc", new RPCServiceImpl()); } }
這個時候啓動服務類,而後就能夠經過地址http://localhost:9966/rpc?wsdl訪問WSDL文件了了:編碼
<?xml version="1.0" encoding="UTF-8"?> <!-- 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 name="RPCServiceImplService" targetNamespace="http://rpc.hqs.com/" xmlns="http://schemas.xmlsoap.org/wsdl/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:tns="http://rpc.hqs.com/" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:wsam="http://www.w3.org/2007/05/addressing/metadata" xmlns:wsp1_2="http://schemas.xmlsoap.org/ws/2004/09/policy" xmlns:wsp="http://www.w3.org/ns/ws-policy" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"> <types/> -<message name="RPCMethod"> <part type="xsd:string" name="arg0"/> </message> -<message name="RPCMethodResponse"> <part type="xsd:string" name="return"/> </message> -<portType name="IRPCService"> -<operation name="RPCMethod"> <input message="tns:RPCMethod" wsam:Action="http://rpc.hqs.com/IRPCService/RPCMethodRequest"/> <output message="tns:RPCMethodResponse" wsam:Action="http://rpc.hqs.com/IRPCService/RPCMethodResponse"/> </operation> </portType> -<binding type="tns:IRPCService" name="RPCServiceImplPortBinding"> <soap:binding style="rpc" transport="http://schemas.xmlsoap.org/soap/http"/> -<operation name="RPCMethod"> <soap:operation soapAction=""/> -<input> <soap:body namespace="http://rpc.hqs.com/" use="literal"/> </input> -<output> <soap:body namespace="http://rpc.hqs.com/" use="literal"/> </output> </operation> </binding> -<service name="RPCServiceImplService"> -<port name="RPCServiceImplPort" binding="tns:RPCServiceImplPortBinding"> <soap:address location="http://localhost:9966/rpc"/> </port> </service> </definitions>
接下來咱們就能夠寫客戶端類:url
package com.hqs.rpc; import java.net.MalformedURLException; import java.net.URL; import javax.xml.namespace.QName; import javax.xml.ws.Service; /** * 客戶端類 * @author hqs * */ public class RPCClient { public static void main(String[] args) { try { URL url = new URL("http://localhost:9966/rpc?wsdl"); QName qname = new QName("http://rpc.hqs.com/","RPCServiceImplService"); Service service = Service.create(url, qname); IRPCService irpc = service.getPort(IRPCService.class); System.out.println(irpc.RPCMethod("client")); } catch (MalformedURLException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } RPC Method invoked: client
簡單的RPC就這麼實現了。其實目前實現上一些公司實現的比較複雜,分爲服務分爲provider和consumer,以及負責監控管理的provider,provider通常採用zookeeper單數集羣,用於管理和監控provider的服務註冊,由於provider可能部署在同一臺機器上的不一樣端口或者不一樣機器上,consumer經過zookeeper就能夠拿到provider的IP/接口/版本號/端口等信息,而後進行調用。
好了,若是有不對的地方,請你們指正。