一、四种常用的发布方式
1. CXF方式
Apache CXF是一个开源服务框架。Apache CXF = Celtix + XFire,Apache CXF 的前身叫 Apache CeltiXfire,现在已经正式更名为 Apache CXF 了,以下简称为 CXF。CXF 继承了Celtix和XFire两大开源项目的精华,比如:JAX-WS and JAX-RS,主要特性包括:
l 支持Web services标准。包括:SOAP、the WSI Basic Profile、WSDL、WS-Addressing、WS-Policy、WS-ReliableMessaging、WS-Security、WS-SecureConversation和WS-SecurityPolicy.
l 支持不同类型前端开发模型。CXF实现了JAX-WS APIs,支持JAX-RS开发。
l 容易使用。CXF设计的简洁和直观,具有简洁APIs迅速的构建基于代码的服务,Maven插件使得工具集成更加容易、JAX-WS API支持、Spring 2.x XML使得配置更加容易。
l 支持二进制和遗留协议。CXF被设计为可插拔的架构,在不同的传输协议结合下,不仅支持XML,也支持非XML类型绑定,例如:JSON和CORBA。
缺点是可能与jdk1.5有些不兼容、was6.1.1不兼容,表现在cxf必须的jar包“wsdl4j-1.6.2.jar”报错,报的错为: java.lang.IncompatibleClassChangeError,但是axis2不会,使用cxf+spring搭建WebService:
第一步,添加jar包,自己下载对应jar包
第二步,配置web.xml文件,如下(重要的地方已标记):
<context-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:/applicationContext.xml</param-value> </context-param> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> <!-- Character Encoding filter --> <filter> <filter-name>encodingFilter</filter-name> <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class> <init-param> <param-name>encoding</param-name> <param-value>UTF-8</param-value> </init-param> </filter> <filter-mapping> <filter-name>encodingFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <servlet> <servlet-name>CXFServlet</servlet-name> <servlet-class>org.apache.cxf.transport.servlet.CXFServlet</servlet-class> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>CXFServlet</servlet-name> <url-pattern>/webservice/*</url-pattern> </servlet-mapping> |
上述标记的地方,第一处是spring配置文件路径;第二出是wsdl地址内容;
第三步,编写接口类与实现类,注意注解
接口类 @WebService public interface SendService { public boolean sendOA(@WebParam(name="param")String param); public boolean sendOrg(OrgEntity org); } 实现类 @WebService(endpointInterface="com.service.SendService",serviceName="sendService") public class SendServiceImplimplements SendService{ public boolean sendOA(String param) { System.out.println("-------sendOA---------param:"+param); if(param.equals("zhoujian")){ return true; } return false; } public boolean sendOrg(OrgEntity org) { System.out.println("-------sendOrg--begin-------"); return true; } } |
第四步,Spring配置文件
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p" xmlns:jaxws="http://cxf.apache.org/jaxws" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd"> <import resource="classpath:META-INF/cxf/cxf.xml"/> <import resource="classpath:META-INF/cxf/cxf-extension-soap.xml"/> <import resource="classpath:META-INF/cxf/cxf-servlet.xml"/>
<jaxws:endpoint id="sendServie" implementor="com.service.impl.SendServiceImpl" address="/sendServie" />
<!-- <jaxws:client id="sendServiceClient" serviceClass="com.service.SendService" address="http://10.137.138.11:9080/Wb/webservice/sendServie?wsdl" />-->
</beans> |
“jaxws:client”该标签可以不必写,访问时可以手动拼接该url
第五步,发布,直接部署到服务器,访问:
http://10.137.138.11:9080/Wb/webservice/sendServie?wsdl |
2. Xfire方式
xfire方式已经很老了,现在用的少了,但是我现在的项目还是使用的,这是之前的同事们做的,不知道是怎么考虑的
Xfire方式发布webservice:
第一步,添加jar包,下载对应jar包
第二步,修改web.xml文件
<servlet> <servlet-name>XFireServlet</servlet-name> <servlet-class>org.codehaus.xfire.transport.http.XFireConfigurableServlet</servlet-class> <load-on-startup>0</load-on-startup> </servlet> <servlet-mapping> <servlet-name>XFireServlet</servlet-name> <url-pattern>/services/*</url-pattern> </servlet-mapping> |
第三步,编写接口类
接口类: public abstract interface IBankingService { public abstract String transferFunds(String paramString1); } 实现类: public class BankingService implements IBankingService{ public String transferFunds(String fromAccount) { return fromAccount+":ok"; } } |
第四步,编写services.xml配置文件
在WEB-INF目录下新建目录META-INF,在该目录下新建文件夹xfire,该目录下新建文件services.xml
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://xfire.codehaus.org/config/1.0"> <service> <name>Banking</name> <namespace>mybank</namespace> <serviceClass> com.mybank.xfire.example.IBankingService </serviceClass> <implementationClass> com.mybank.xfire.impl.BankingService </implementationClass> </service> </beans> |
第五步,发布,部署到服务器,访问url:
http://localhost:9080/Xfire/services/Banking?wsdl |
3. AXIS2方式
Axis2发布WebService有两种方式,其一是利用axis2插件打成aar包放到axis_war里面部署到服务器发布;其二是不打包发布(本例);我不清楚打包发布有什么好处,感觉很麻烦项目外还得部署一个war,现在介绍第二种不打包的方式,类似xfire,同时由于cxf与was不兼容导致wsdl.jar报错,但是xfire与axis2也用到wsdl.jar却不报错
Axis2发布WebService:
第一步,添加jar包,下载对应jar包
第二步,修改web.xml文件
<servlet> <servlet-name>AxisServlet</servlet-name> <servlet-class>org.apache.axis2.transport.http.AxisServlet</servlet-class> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>AxisServlet</servlet-name> <url-pattern>/services/*</url-pattern> </servlet-mapping>
|
第三步,编写实现类
public class ServiceImpl { public String sayHello(String name){ System.out.println("================"); return "hello:"+name; } } |
第四步,增加WEN-INF内容
将axis.war解压下的WEN-INF文件夹内的conf、modules复制到项目WEB-INF下
第五步,在WEB-INF下创建文件夹services(名字不可改),在该目录下创建文件夹(名称随意),在该目录下创建文件夹META-INF(名称不可改),在该目录下创建文件services.xml(名称不可改),该文件内容为:
<?xml version="1.0" encoding="UTF-8"?> <service name="axisDemo"> <description> Web Service例子 </description> <parameter name="ServiceClass"> com.ServiceImpl </parameter> <messageReceivers> <messageReceiver mep="http://www.w3.org/2004/08/wsdl/in-out" class="org.apache.axis2.rpc.receivers.RPCMessageReceiver" /> <messageReceiver mep="http://www.w3.org/2004/08/wsdl/in-only" class="org.apache.axis2.rpc.receivers.RPCInOnlyMessageReceiver" /> </messageReceivers> </service> |
第六步,部署到服务器,发布URL为:
http://localhost:9080/Axis2Test/services/axisDemo?wsdl |
4. AXIS1方式
第一步,添加jar包
第二步,修改web.xml
<servlet> <servlet-name>AxisServlet</servlet-name> <servlet-class> org.apache.axis.transport.http.AxisServlet </servlet-class> </servlet> <servlet-mapping> <servlet-name>AxisServlet</servlet-name> <url-pattern>/services/*</url-pattern> </servlet-mapping> |
第三步,实现类与实体类
实现类: package com; public class Axis { public String sayHello(String name){ System.out.println("============:"+name); return "hi:"+name; } public String sayHelloToUser(User u){ System.out.println("============:"+u.getId()); System.out.println("============:"+u.getPath()); System.out.println("============:"+u.getAdd()); return "hi:"+u.getName(); } }
实体类: package com; public class User { private String id; private String name; private String add; private String path;
getter setter ……方法
|
第四步,创建配置文件:在WEB-INF下新建文件“server-config.wsdd”
<?xml version="1.0" encoding="UTF-8"?> <deployment xmlns="http://xml.apache.org/axis/wsdd/" xmlns:java="http://xml.apache.org/axis/wsdd/providers/java"> <!--globalConfiguration 标签内容为系统默认 无需更改à <globalConfiguration> <parameter name="adminPassword" value="admin"/> <parameter name="attachments.Directory" value="./attachments"/> <parameter name="attachments.implementation" value="org.apache.axis.attachments.AttachmentsImpl"/> <parameter name="sendXsiTypes" value="true"/> <parameter name="sendMultiRefs" value="true"/> <parameter name="sendXMLDeclaration" value="true"/> <parameter name="axis.sendMinimizedElements" value="true"/> <requestFlow> <handler type="java:org.apache.axis.handlers.JWSHandler"> <parameter name="scope" value="session"/> </handler> <handler type="java:org.apache.axis.handlers.JWSHandler"> <parameter name="scope" value="request"/> <parameter name="extension" value=".jwr"/> </handler> </requestFlow> </globalConfiguration> <handler name="LocalResponder" type="java:org.apache.axis.transport.local.LocalResponder"/> <handler name="URLMapper" type="java:org.apache.axis.handlers.http.URLMapper"/> <handler name="Authenticate" type="java:org.apache.axis.handlers.SimpleAuthenticationHandler"/> <!—service 标签是需要配置的-à <!—name是url中需要的参数-à <service name="axisTest" provider="java:RPC"> <!—allowedMethods 的value值是方法名 可以写*-à <parameter name="allowedMethods" value="*"/> <!—className的value值是类路径-à <parameter name="className" value="com.Axis"/> <!—wsdlTargetNamespace的wsdl文件中TargetNamespace的值-à <parameter name="wsdlTargetNamespace" value="http://service.impl.tdi.taikang.tivoli.ibm.com/"/> <!—此处很重要,若方法需要传实体类,则配置此处-à <beanMapping qname="myNS:User" xmlns:myNS="urn:BeanService" languageSpecificType="java:com.User"/> </service> <!—默认-à <transport name="http"> <requestFlow> <handler type="URLMapper"/> <handler type="java:org.apache.axis.handlers.http.HTTPAuthHandler"/> </requestFlow> </transport> <transport name="local"> <responseFlow> <handler type="LocalResponder"/> </responseFlow> </transport> </deployment> |
第五步,部署,同上。
5. AXIS1客户端调用
此处调用方式为axis1的调用,需要传递的参数可以是字符串或实体类,字符串方式:
Service service = new Service(); Call call = (Call) service.createCall(); //wsdl地址 call.setTargetEndpointAddress(new URL(wsdlUrl)); //设定调用3分钟不返回则超时 call.setTimeout(new Integer(180000)); //命名空间(wsdl文件中的targetNameSpace属性值)以及方法名 call.setOperationName(new QName("http://com","sayHello")); //参数类型 call.addParameter("name", XMLType.XSD_STRING, ParameterMode.IN); //返回值类型 call.setReturnType(XMLType.XSD_STRING); //参数值 String retXML2 = (String) call.invoke( new Object[] {"yczhang" }); System.out.println( retXML2); |
实体类方式(调用axis2的接口有点问题):
UserEntity userEntry = new UserEntity(); userEntry.setId("yczhang"); userEntry.setName("yczhang"); Service service = new Service(); Call call = (Call) service.createCall(); //wsdl地址 call.setTargetEndpointAddress(new URL(wsdlUrl)); //设定调用3分钟不返回则超时 call.setTimeout(new Integer(180000)); //命名空间(wsdl文件中的targetNameSpace属性值)以及方法名 call.setOperationName(new QName("http://com","sayHelloToUser")); //注册SimpleObject的序列化类型 QName qn = new QName("urn:BeanService","UserEntity"); call.registerTypeMapping(UserEntity.class, qn,new BeanSerializerFactory(UserEntity.class, qn),new BeanDeserializerFactory(UserEntity.class, qn)); //参数类型(可省略) call.addParameter("requestParam", org.apache.axis.encoding.XMLType.XSD_ANYTYPE, ParameterMode.IN); //返回值类型 call.setReturnType(XMLType.XSD_BOOLEAN); Boolean retXML1 = (Boolean) call.invoke( new Object[] {userEntry }); System.out.println( retXML1); |
注意,实体类方式,当调用的是由axis2方式所发布的接口时,容易出现问题,表现在所传递的实体类的属性内容为null,但在该实体类内新建一属性传如该值时,却有值。应该是axis1对axis2的不兼容问题。并且调用axis2的接口时,需要在客户端写出namespace,即:
//call.setOperationName(new QName("http://localhost:9080/WS_Axis/services/axisTest", "sayHelloToUser"));
|
该种调用方式对于axis1的接口没问题。泰康项目最终使用的是axis1发布的接口,并使用该种方式调用的。
public static void main(String[] args)throws ServiceException, MalformedURLException, RemoteException { String wsdlUrl = "http://localhost:9080/WS_Axis/services/axisTest?wsdl"; //实体类 User user = new User(); user.setId("1"); user.setAdd("test"); user.setName("test"); user.setPath("test"); Service service = new Service(); Call call = (Call) service.createCall(); call.setTargetEndpointAddress(new URL(wsdlUrl)); //设定调用3分钟不返回则超时 call.setTimeout(new Integer(180000)); //call.setOperationName(new QName("http://localhost:9080/WS_Axis/services/axisTest", "sayHelloToUser")); //注册SimpleObject的序列化类型(urn:BeanService在wsdd文件内有配置) QName qn = new QName("urn:BeanService","User"); call.registerTypeMapping(User.class, qn,new BeanSerializerFactory(User.class, qn),new BeanDeserializerFactory(User.class, qn)); //方法名 call.setOperationName("sayHelloToUser"); //“user”是接口服务端方法体中的实体类所声明的变量名(”say(User user)”) call.addParameter("user", org.apache.axis.encoding.XMLType.XSD_ANYTYPE, ParameterMode.IN); //返回值类型 call.setReturnType(XMLType.XSD_STRING); System.out.println( call.invoke(new Object[] { user })); } |
6. AXIS2客户端调用
具体代码:
public class RPClient { public static void main(String[] args)throws AxisFault { try { //实体类 UserEntity ue = new UserEntity(); ue.setId("123"); ue.setAddress("test"); ue.setMail("123"); ue.setName("yczhang"); RPCServiceClient client = new RPCServiceClient(); Options options = client.getOptions(); String url = "http://localhost:9080/WS_Axis2/services/axisDemo?wsdl"; EndpointReference end = new EndpointReference(url); options.setTo(end);
Object[] obj = new Object[] { ue }; Class<?>[] classes = new Class[] { Boolean.class }; //命名空间 方法名 QName qname = new QName("http://com","sayHelloToUser"); System.out.println(client.invokeBlocking(qname, obj, classes)[0]); } catch (AxisFault e) { e.printStackTrace(); } } |
注意 该种方式缺点是客户端实体类路径即包名必须与服务端实体类路径相同!!!但该方式可以调任何方式编写的接口!!!!
7. CXF客户端调用
使用axis、axis2客户端调用cxf接口会有问题,建议使用cxf自身客户端调用或者使用webservice Client 自动生成客户端方式,jar包自己下载
功能代码:
public class TT { public static void main(String[] args) { JaxWsDynamicClientFactory dcf = JaxWsDynamicClientFactory.newInstance(); Client client = dcf.createClient("http://10.137.138.11:9080/WS_CXF/webservice/sendServie?wsdl"); try { //此处http://service.com/需要指向接口路径而非实现类 System.out.println(client.invoke(new QName("http://service.com/","sendOA"),"test")[0]); } catch (Exception e) { e.printStackTrace(); } } } |
注意:若运行程序时报错“JAXB 2.0 API ….. endorsed”则需要将以下jar包放入jdk lib和jre li,重启exlipse即可。
8. Web Service Client客户端调用
调用代码如下:
public class CXFClient {
public static void main(String[] args)throws Exception, IllegalAccessException, InvocationTargetException {
JaxWsDynamicClientFactory dcf = JaxWsDynamicClientFactory.newInstance();
Client client = dcf.createClient("http://localhost:9080/WS_CXF/webservice/sendServie?wsdl");
client.invoke("sendOA", "aa");
}}
二、几种发布方式的性能比较
这些数据是从别人哪里
从数据可以看出,有下面几个特点:
l 客户端初次调用,初始化客户端stub对象时,大约在:600ms~2500ms。由于需要建立网络连接,初始化java相关对象,因此耗时较长。
l 客户端初始化stub后,接口初次调用,大约在:400ms~1000ms。相比后续的接口调用时间最长。
l 在第一次调用完毕后,随后的调用中,性能都明显提升。大约在:7ms~30ms。
l 本机测试与远程测试,性能上差距很微小,在高速的局域网内,性能差别几乎可以忽略。
l 在相同的服务端下,采用不同框架生成的stub代码调用时,时间上也存在一定的差异。
实际应用中,接口的调用都是在网络的不同的机器之间进行,本文也重点关注远程调用测试结果,在测试结果比较上,可以看出:
l 最优组合是最差组合性能的5倍多。
n 最优的组合为:cxf客户端+ cxf服务端,6ms左右。
n 最差的组合为:axis1客户端+ axis1服务端,32ms左右。
l CXF作为服务端,对于不同的客户端调用时,性能最佳。
从以上的结果进行分析得出用Axis2与CXF作为服务器端效率是比两外两者(Axis1与xfire)要高,所以下面就对CXF与Axis2进行对比
1. 选择能够对我们的开发过程提供更多、更好帮助的Web开发框架
(CXF与Axis2都是apache的开源框架,也是目前比较流行的webservice框架,)(百度加个人观点)
2. 开发框架的学习一定要简单,上手一定要快,没有什么比使用能得到更深的体会。那些动不动就需要半个月或者一个月学习周期的框架,实在是有些恐怖。(cxf学习成本比axis2低)【Axis2允许自己作为独立的应用来发布Web Service,并提供了大量的功能和一个很好的模型,这个模型可以通过它本身的架构(modular architecture)不断添加新的功能。有些开发人员认为这种方式对于他们的需求太过于繁琐。这些开发人员会更喜欢CXF。 】【CXF更注重开发人员的工效(ergonomics)和嵌入能力(embeddability)。大多数配置都可以API来完成,替代了比较繁琐的XML配置文件, Spring的集成性经常的被提及,CXF支持Spring2.0和CXF's API和Spring的配置文件可以非常好的对应。CXF强调代码优先的设计方式(code-first design),使用了简单的API使得从现有的应用开发服务变得方便。】{百度观点}
3. 一定要能得到很好的技术支持,在应用的过程中,或多或少都会出现这样或者那样的问题,如果不能很快很好的解决,会对整个项目开发带来影响。一定要考虑综合成本,其实这是目前应用开源软件最大的问题,碰到问题除了死肯文档就是查阅源代码,或者是网上搜寻解决的办法,通常一个问题就会导致1-2天的开发停顿,严重的甚至需要一个星期或者更长,一个项目有上这么几次,项目整体的开发成本嗖嗖的就上去了。(所以个人感觉应该选择比较流行的框架,起码碰到问题还能上网搜索)
4. 开发框架结合其他技术的能力一定要强(个人感觉和下同)
5. 开发框架的扩展能力一定要强。在好的框架都有力所不及的地方,这就要求能很容易的扩展开发框架的功能,以满足新的业务需要。同时要注意扩展的简单性,如果扩展框架的功能代价非常大,还不如不用呢。(axis2与cxf 都支持很多优秀的框架(上已提到),但axis2扩展性比cxf要好,axis2不仅支持java对c/C++提供支持)(个人观点)【RESTEasy也能支持许多比较优秀的框架】(百度加个人观点)
6. 开发框架最好能提供可视化的开发和配置,可视化开发对开发效率的提高,已经得到业界公认。(暂时无法提供观点)
7. 开发框架的设计结构一定要合理,应用程序会基于这个框架,框架设计的不合理会大大影响到整个应用的可扩展性。(暂时无法提供观点)
8. 开发框架一定要是运行稳定的,运行效率高的。框架的稳定性和运行效率直接影响到整个系统的稳定性和效率。(从上面的测试来看,cxf的效率要高于axis2,不知道在大并发量的时候系统的稳定性和安全性)
9. 开发框架一定要能很好的结合目前公司的积累。在多年的开发中已有了很多积累,不能因为使用开发框架就不能再使用了,那未免有些得不偿失。(暂时无法提供观点)
10. 选择开发框架另外要注意的一点就是:任何开发框架都不可能是十全十美的,也不可能是适应所有的应用场景的,也就是说任何开发框架都有它适用的范围。所以选择的时候要注意判断应用的场景和开发框架的适用性。(暂时无法提供观点)
总结:
Apache CXF是CodehausXFire的第二代产品,目前在不同框架中性能最佳,应该是开发者不错的选择,这与它本身的架构设计不无关系。相比其他框架,CXF具有几个突出的特性:支持JAX-WS、Spring集成、Aegi数据绑定、支持RESTful services、支持WS-*、Apache协议、代码实现简洁。
Apache Axis2是Apache Axis1的第二代产品,架构上也非常不错,关键特性:支持多语言(C/C++)、支持各种规范、可插拔模块化设计、支持热部署等。与CXF相比性能也非常优异。
RESTEasy也许也是个不错的框架!(个人观点)
原文:https://www.cnblogs.com/firstdream/p/5575928.html
最近分析的这个系统,逻辑架构中有一层是RPC interface。之前对RPC不熟悉,就上网搜索了一下资料,在此总结一下:
RPC是Remote Procedure Calling,远程过程调用的缩写。并不是“远程进程调用”——Remote Process Calling。RPC总的来说是一个Client/Server的结构,提供服务的一方称为Server,消费服务的一方称为Client。
下图是本地过程调用,所有的过程都在本地服务器上,依次调用即可。
下图则是所谓的远程过程调用,需要在Client和Server中交互。
因此,两种调用方式,会产生什么区别呢?
1、网络传输的开销和编程的额外复杂性。
2、本地过程调用中,过程在同一块物理内存中,因此就可以传递指针了。而远程过程调用则不能,因为远程过程与调用者运行在完全不同的地址空间中。
3、远程过程不能共享调用者的环境,所以它就无法直接访问调用者的I/O和操作系统API。
简单来说,就是远程过程调用会比本地过程调用复杂。除了性能的额外开销之外,编程也复杂得多。
至少可以想到,交互双方需要能够封装数据结构,理解协议,处理连接等等,确实是很麻烦的。可能一个很简单的调用,却需要做很多的编程工作。所以,为了简化RPC调用的编程,就提出了一个RPC的标准模型。
下面是RPC的原理草图。
可以看到,该模型中多了一个stub的组件,这个是约定的接口,也就是server提供的服务。注意这里的“接口”,不是指JAVA中的interface,因为RPC是跨平台跨语言的,用JAVA写的客户端,应该能够调用用C语言提供的过程。
对客户端来说,有了这个stub,RPC调用过程对client code来说就变成透明的了,客户端代码不需要关心沟通的协议是什么,网络连接是怎么建立的。对客户端来说,它甚至不知道自己调用的是一个远程过程,还是一个本地过程。
然后,前面说的理解协议,处理连接的工作,总是要有人做的,这个工作就是在下面的RPC Interface里完成的。
最近几年,遇到这种场景(需要调用远程机器上的服务),往往会考虑用web service来完成,其实我认为web service和RPC是非常相像的,下面是web service的原理草图
对比一下RPC草图,就会发现非常的接近。在组件层次,和交互时序上完全没有差别,只是方框内的字不一样,但是实际上承担的职责却是完全对应的。
web service接口就是RPC中的stub组件,规定了server能够提供的服务(web service),这在server和client上是一致的,但是也是跨语言跨平台的。同时,由于web service规范中的WSDL文件的存在,现在各平台的web service框架,都可以基于WSDL文件,自动生成web service接口。
下面的web service框架,根据所选的平台有所不同,比如在JAVA平台中,现在最流行的是apache的cxf框架。它做的事情也和RPC Interface是一样的,负责解析协议(SOAP协议),负责处理连接(建立HTTP连接)。
因此,我认为RPC和web service非常得接近,只是RPC的传输层协议,以及应用层协议,可以自行实现,所以选择的余地更大一点。可能会在性能和传输效率上,有更大的优势(不一定) 。
和web service有很多成熟框架可供选择一样,RPC也有很多现成的框架可供选择,比如在JAVA平台上有nfs-rpc等。
总结来说,要实现远程过程调用,需要有3要素:
1、server必须发布服务。
2、在client和server两端都需要有模块来处理协议和连接。
3、server发布的服务,需要将接口给到client。
当然,应用协议是什么样的,怎么连接,服务接口怎么给到client,是可以自行实现的,选择余地很大。但是RPC协议提供了一种标准的建议,如果没有特别的理由,我认为没有必要自行实现,但是清楚这个原理,总是好的。
最后回到我最近正在分析的系统上来说。本文一开始就提到,它的架构中有一个RPC Interface。
由于这不是一个开源系统,所以我并不清楚它的RPC Interface的实现,也就是说,我并不清楚它的应用协议和传输协议是什么。姑且假设它是用的标准RPC协议的。
但是它将server服务发布给client的方式,是向client提供了API,对JAVA平台的程序员来说,就是一个xxx.jar。
这个jar包里,有2部分内容:
1、client stub,包括接口和封装过的数据结构。即ServerService,和XXXForm、XXXFilter等。那对于client程序员来说,就只需要调用ServerService.xxxx()的方法,并组装XXXForm对象作为参数即可,类似
public interface ServerService{
public XXXFilter giveMeTheFilter(XXXForm form);
}
程序员只需要关心怎么封装合适的XXXForm,以及什么时候调用giveMeTheFilter()方法即可,底层的协议,server端的实现,对client程序员来说都是透明的。
2、RPC Interface层的实现。这部分就做了协议解析、连接处理、异常处理等,但这部分类,是不对client程序员开放的。这种通过API(SDK),向client发布服务的方式,我认为是有可取之处的。
原文:https://www.cnblogs.com/aspirant/p/8631089.html
四、高性能RPC框架Dubbo
Dubbo是阿里巴巴公司开源的一个高性能优秀的服务框架,使得应用可通过高性能的 RPC 实现服务的输出和输入功能,可以和 Spring框架无缝集成。
Dubbo是一款高性能、轻量级的开源Java RPC框架,它提供了三大核心能力:面向接口的远程方法调用,智能容错和负载均衡,以及服务自动注册和发现。(摘自百度百科)