本文是《分布式java应用基础与实践》读书笔记;另外参考了 此博客 ,感觉讲的挺好的,尤其是其中如下内容:
另外,消息方式实现系统间通信本文不涉及。RMI则只采用spring RMI框架来实现效果,更多的则是来讲讲webService及效果。
RMI (Remote Method Invocation) ----》 spring RMI(配置及实现直接参考spring文档,已经很详细了)
spring RMI工作原理图如下:
RMI代码结构图:
服务端代码
接口Business.java:
package com.rmi.server; public interface Business { /** * 显示客户端提供的消息,并返回 * @param message * @return */ public String echo(String message); } View Code
接口实现类BusinessImpl.java:
package com.rmi.server; public class BusinessImpl implements Business { @Override public String echo(String message) { if("quit".equalsIgnoreCase(message.toString())){ System.out.println("Server will be shutdown!"); System.exit(0);; } System.out.println("Message from client:" + message); return "Server response:" + message; } } View Code
spring RMI配置文件spring-server.xml:
View Code
服务启动类:
package com.rmi.server; import org.springframework.context.support.ClassPathXmlApplicationContext; public class ServerMain { public static void main(String[] args) throws Exception{ new ClassPathXmlApplicationContext("classpath:spring-server.xml"); System.out.println("Server has been started..."); } } View Code
客户端代码
配置文件spring-client.xml:
View Code
客户端调用服务java:
package com.rmi.client; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import com.rmi.server.Business; public class ClientMain { public static void main(String[] args) { ApplicationContext ac = new ClassPathXmlApplicationContext("classpath:spring-client.xml"); Business bn = (Business) ac.getBean("businessService"); System.out.println(bn.echo("hello")); } } View Code
测试结果
先启动服务端,再运行客户端
调用成功!
测试补充
1.多了个可以选择的ip
在启动服务的时候,注意了下输出信息,如下图
当时就纳闷了,这个ip是哪来的,服务器端(在Windows系统上)的ip不是192.168.1.101吗,怎么崩出来个192.168.56.1?,后来ipconfig下
发现那个ip是安装virtualbox后,路由分配给它的ip,测试发现,客户端调用时的ip写两个中的任意一个都是可以的,都是能成功调用的!如果没用虚拟机软件的话是不存在这个现象的。
所以大家写的时候写服务器端的ip是肯定不会错的!
2.服务器端与客户端分离
之前测试时,客户端与服务器端是在一台机器上的,访问能成功,那么将两者分开了?
windows环境(192.168.1.101)做服务器端,启动个虚拟机做客户端(192.168.1.111)做客户端,将原来客户端代码移到111上(有些许差别,服务器端的接口class文件------Business接口 需要拷贝过去,不然客户端代码报错)。
测试结果怎么都是连接超时,无论客户端调用的是192.168.1.101还是192.168.56.1。资料查了一些,没能解决,希望知道的朋友可以在评论区留言,帮兄弟我解决此问题!
因为重点在webService上,上面的问题我先放一放。
webService
1.概念
大家可以去看看 这篇博客 ,个人感觉webService的相关概念解释的挺清楚的。
简而言之: WebService是一种跨编程语言和跨操作系统平台的远程调用技术。
所谓跨编程语言和跨操作平台,就是说服务端程序采用java编写,客户端程序则可以采用其他编程语言编写,反之亦然!跨操作系统平台则是指服务端程序和客户端程序可以在不同的操作系统上运行。
所谓远程调用,就是一台计算机a上的一个程序可以调用到另外一台计算机b上的一个对象的方法,譬如,银联提供给商场的pos刷卡系统,商场 的POS机转账调用的转账方法的代码其实是跑在银行服务器上。再比如,amazon,天气预报系统,淘宝网,校内网,百度等把自己的系统服务以webservice服务的形式暴露出来,让第三方网站和程序可以调用这些服务功能,这样扩展了自己系统的市场占有率。
其实可以从多个角度来理解WebService,从表面上看,WebService就是一个应用程序向外界暴露出一个能通过Web进行调用的 API,也就是说能用编程的方法通过Web来调用这个应用程序。我们把调用这个WebService的应用程序叫做客户端,而把提供这个 WebService的应用程序叫做服务端。从深层次看,WebService是建立可互操作的分布式应用程序的新平台,是一个平台,是一套标准。它定义 了应用程序如何在Web上实现互操作性,你可以用任何你喜欢的语言,在任何你喜欢的平台上写Web service ,只要我们可以通过 Web service标准对这些服务进行查询和访问。
WebService平台需要一套协议来实现分布式应用程序的创建。任何平台都有它的数据表示方法和类型系统。要实现互操作性,WebService平台 必须提供一套标准的类型系统,用于沟通不同平台、编程语言和组件模型中的不同类型系统。Web service平台必须提供一种标准来描述 Web service,让客户可以得到足够的信息来调用这个Web service。最后,我们还必须有一种方法来对这个Web service进行远 程调用,这种方法实际是一种远程过程调用协议(RPC)。为了达到互操作性,这种RPC协议还必须与平台和编程语言无关。
2.要素
XML和XSD:可扩展的标记语言是Web Service平台中表示数据的基本格式。除了易于建立和易于分析外,XML主要的优点在于它既与平台无关,又与厂商无关。
WSDL:Web Service Description Language,网络服务描述语言,描述服务所使用的协议、所期望的参数、返回的参数格式等。
SOAP:Simple Object Access Protocol,简单对象访问协议;soap协议是基于HTTP协议的,soap也是基于XML和XSD的,XML是soap的数据编码方式。打个比喻:HTTP就是普通公路,XML就是中间的绿色隔离带和两边的防护栏,soap就是普通公路经过加隔离带和防护栏改造过的高速公路。
UDDI: Universal Description, Discovery, and Integration ,是一套基于web的、分布式的、为web service提供的信息注册中心的实现标准规范;相当于是一个注册中心,以便被客户发现,更容易被找到。基本用不到,这里只是提一下。
3.开发
服务端开发:把公司内部系统的业务方法发布成WebService服务,供远程合作单位和个人调用。(借助一些WebService框架可以很轻松地把自己的业务对象发布成WebService服务,Java方面的典型WebService框架包括:axis,xfire,cxf 等,java ee服务器通常也支持发布WebService服务,例如JBoss。)
客户端开发:调用别人发布的WebService服务,大多数人从事的开发都属于这个方面,例如,调用天气预报 WebService服务。
WebService的工作调用原理:对客户端而言,我们给这各类WebService客户端API传递wsdl文件 的url地址,这些API就会创建出底层的代理类,我调用这些代理,就可以访问到webservice服务。代理类把客户端的方法调用变成soap格式的请求数据再通过HTTP协议发出去,并把接收到的soap数据变成返回值返回。对服务端而言,各类WebService框架的本质就是一个大大的Servlet,当远程调用客户端给它通过http协议发送过来soap格式的请求数据时,它分析这个数据,就知道要调用哪个java类的哪个方法,于是去查找或创建这个对象,并调用其方法,再把方法返回的结果包装成soap格式的数据,通过http响应消息回给客户端。
4.实现 (基于CXF开源框架)
CXF工作原理图
代码结构图
为了省事,cxf的lib下的所有jar文件(不包括文件夹和WHICH_JARS)全部导入到了工程中。
服务端代码
接口HelloWorld.java
package demo.hw.server; public interface HelloWorld { String sayHi(String name); } View Code
接口实现HelloWorldImpl.java
package demo.hw.server; public class HelloWorldImpl implements HelloWorld { public String sayHi(String name) { System.out.println("sayHi called"); return "Hello " + name; } } View Code
服务启动Server.java
package demo.hw.server; import org.apache.cxf.frontend.ServerFactoryBean; public class Server { public Server() throws Exception{ HelloWorldImpl hw = new HelloWorldImpl(); ServerFactoryBean sfb = new ServerFactoryBean(); sfb.setServiceClass(HelloWorld.class); sfb.setServiceBean(hw); sfb.setAddress("http://192.168.1.101:9000/Hello"); sfb.create(); } public static void main(String[] args) throws Exception{ new Server(); System.out.println("server start ..."); Thread.sleep(5*60*1000); System.out.println("server exit ..."); System.exit(0); } } View Code
客户端代码
启动Client.java
package demo.hw.client; import org.apache.cxf.frontend.ClientProxyFactoryBean; import demo.hw.server.HelloWorld; public final class Client { public static void main(String[] args) { ClientProxyFactoryBean clientFactory = new ClientProxyFactoryBean(); clientFactory.setAddress("http://192.168.1.101:9000/Hello"); HelloWorld hw = clientFactory.create(HelloWorld.class); System.out.println(hw.sayHi("Hi")); } } View Code
启动服务,如下图
调用服务,运行客户端代码,如下图,服务调用成功!
这里测的时候,客户端与服务端在一台机器上,那么不在一台机器上是个什么情况了?我们将客户端移到虚拟机192.168.1.111上(服务端唉192.168.1.101上),如下图
结果显示,测试成功!
总结
一般而言,开源框架都会有详细的文档讲解,大家用的时候最好去阅读它的文档,就好象spring rmi,它的文档就将的挺详细的,你去看的时候还会发现,spring也有他的webService实现;cxf没有文档,只有api,但是他提供了很多的样例,在samples文件夹下,子文件看名字就知道其下的样例实现的是什么功能,我的cxf示例就是参考的java_first_pojo文件夹。老外写的官方文档其实还是挺好读的!
其他的一些开源框架像axis2等,我就没去实践了,大同小异,大家有时间可以去实践下。
另外我文中的那个问题,希望有伙伴帮我解答下!
还是那句话: 看的浅,试了才知深!