学完了Java接口后,本节学习RPC(remote procedure call)远程过程调用协议。就是——不同进程之间的方法调用
webservice是什么:HTML+xml (跨语言,跨平台,系统间调用的解决方案)
假设我们有一个OA项目,用Java语言写的,另外有一个项目,CRM项目,用.NET语言写的。
现在我要在两个系统之间整合起来:OA想要CRM项目的一些信息。
【当然,可以连接到CRM的数据库,可是这样,太暴力了,容易干掉对方的数据库】
因此我是怎么做的?用webservice,即:我(CRM)向你暴露一个地址,你(OA)一访问可以得到一个xml,你通过这个xml可以得到一个方法,
CRM暴露了一个接口【wsdl地址】,我(OA)一访问可以生成一个xml,得到一个类。我生成类之后我可以调用CRM类里面的方法。【图左框调用图右框】
不同"类"直接的方法调用——调用OA方框里的方法,实际上是CRM框里的method()方法将被调用:OA传参数到CRM,CRM方法有返回值,就是OA方法的返回值
为什么OA方法能调用CRM方法?因为你OA里的类其实是CRM的一个接口。【得到代理对象就可以得到目标函数的方法了】
其实,我们在OA端得到了CRM端的代理对象
左边里有一个代理对象,代理对象里面定义了一个方法,而目标对象里面也定义了一个方法,
因此,我们一调用代理对象,其实是在目标类里面【右边】 调用了目标方法
RPC是一样的,【是不同进程】。
OA运行在一台机器上,CRM运行在一台机器上,这是两个不同的进程,可以通过网络进行通信了。就是RPC通信——不同进程之间的方法调用(一个进程的一个类,可以调用另外一个进程的类的方法)
现在要通过hadoop来实现“不同进程的方法调用” 因为hadoop对RPC提供了支持【因为有一些工具类】
客户端跟namenode通信,datanode跟namenode通信,都要用到RPC协议。所以,想要看懂源码,就一定要会RPC
我RPCServer里的方法将被调用,将在客户端被调用
服务端server的代码如下: 名称RPCServer.java
会被客户端调用,客户端会得到我服务端的一个代理对象,JDK有个默认的动态代理,动态代理有个前提,客户端和服务端要同时实现一个接口
eclipse里面的快捷键Extract Local Variable这个对应的快捷键是什么:alt+shift+l。
- package cn.itcast.hadoop.rpc;
- import java.io.IOException;
- import org.apache.hadoop.HadoopIllegalArgumentException;
- import org.apache.hadoop.conf.Configuration;
- import org.apache.hadoop.ipc.RPC;
- import org.apache.hadoop.ipc.RPC.Server;
- public class RPCServer implements Bizable{ //定义了一个接口叫Bizable
- //RPC里面应该有一个方法,我的客户端【不同进程】可以调用我这里的方法,于是我写一个方法
- public String sayHi(String name){
- return "HI~ " + name;
- }
- public static void main(String[] args) throws Exception {
- //我现在要使用Hadoop提供的工具类来完成RPC通信,【如果不用工具类,自己写底层很麻烦】
- Configuration conf = new Configuration();
- Server server= new RPC.Builder(conf).setProtocol(Bizable.class).setInstance(new RPCServer()).setBindAddress("192.168.8.100").setPort(9527).build(); //每个都set一下,暂时还没有完全看懂。待2刷
- server.start();
- }
- }
那么,我客户端【左边】得到了服务端server的一个“代理对象”,那么,我客户端和服务端要同时实现一个接口,比如,我的RPC 接着implement Bizable,然后报错,我们点击“创建接口”
创建接口之后,我们得到了一个接口
在接口里面定义一个方法,定义的还是 Bizable.java
- package cn.itcast.hadoop.rpc;
- public interface Bizable {
- public static final long versionID = 100000;
- public String sayHi(String name);
- }
几点说明:1.versionID=10010这个,好像是Hadoop2.0里面的东西,RPC里必须加上versionID 跟前面的version必须相同
2.在接口里的bizable,里面的函数不需要再写一遍,只需要写
- public String sayHi(String name);
后面加分号即可。不需要大括号或什么
客户端client的代码如下:名称RPCClient.java
- package cn.itcast.hadoop.rpc;
- import java.io.IOException;
- import java.net.InetSocketAddress;
- import org.apache.hadoop.conf.Configuration;
- import org.apache.hadoop.ipc.RPC;
- public class RPCClient {
- public static void main(String[] args) throws Exception {
- //client的目的:得到server的代理对象,就可以调用目标对象的方法
- Bizable proxy = RPC.getProxy(Bizable.class, 10010, new InetSocketAddress("192.168.8.100",9527), new Configuration());
- String result = proxy.sayHi("tomcat");
- System.out.println(result);
- RPC.stopProxy(proxy);
- //打印是在客户端打印的,但是,拼接字符串是在服务端【的方法】里拼接的
- }
- }
运行出现了问题,以下是解决办法:
1、将jar包放到linux运行出现了Unsupported major.minor version 51.0
经过网上搜索发现了问题产生的原因:用jdk7编译的class文件放到基于jdk6运行在tomcat之中,就会报这个错。
解决起来也很方便:打开exclipse中项目上的属性—java compiler–选择一个合适的版本后重新编译即可。
具体步骤
解决:项目------>右键------>属性------>Java Compiler------>Compiler Compliance Level------>选择你使用的JDK版本------>应用。
总结:不同的JDK版本使用的major.minor不同,所以会导致这个错误。在项目中要使用当前电脑配置的JDK版本,切忌张冠李戴。
也就是说如果你换成了Exception的话除了能捕捉到IOException还能捕捉到其他的。。如果同时用的话,必须是先用范围小的也就是IOException捕捉 然后再用范围大的Exception捕捉;反过来是不成立,因为Exception所有的异常都捕捉完了,那还要IOException捕捉什么呢?
运行中我抛出异常Exception时出现以下两个代码没用过的提醒,所以我暂时改为抛出异常IOException,不知道原因
import java.io.IOException;
import org.apache.hadoop.HadoopIllegalArgumentException;
把jar包放到linux上运行实现不同客户端调用
window起一个server,然后再linux下运行client【不同客户端之间方法调用】
打Java包:
Java项目右键——导出——Runnable JAR file,点next,选RPCClient,写文件名,完成
把Java包放到linux上
java -jar RPC.jar就可以
也可以设置断点在return "HI~" + name;这里,点击调试运行,再在linux上运行jar包,可以看到当你在eclipse上继续运行后,最后可以在linux上收到HI~tomcat
RMI远程方法调用
在这里插一句:有关源码的问题
正常情况下,我们写的东西是.java的程序,这个就是源码,编译器(compiler)把我们编译成.class的【二进制字节码文件】文件,然后解释器进行解释,翻译,才能运行。
因此,我们平常直接使用的类,是直接使用class,是看不到它的源码的,除非你关联源码
关联源码之后,可以按住Ctrl【或者鼠标点那个位置,然后按住F3】,然后点击那个class类,之后便可以打开这个类的源码,可以看到它的具体东西。
如何关联源码?Java自己的源码,在安装的C盘C:\Program Files\Java\jdk1.7.0_21 这里面的一个src解压文件,之后关联进去即可。
具体如何做,有一篇文章,讲述得比较详细:
http://wenku.baidu.com/link?url=boCg7Q8RxRGUBqNzayZjOVm3paDbVP0bZECNsuP8w3qdgqxzsZ_5tOyjxmVAr6G9BJjLrcdl8BrBJLGlS5tJvmf-HdS76SkLA0kBZIsQsHC
我们使用hadoop,还要关联hadoop的一些源码,否则,hadoop里的一些类,我们能用,但是看不了源码。
比如说,我的datanode和namenode他们俩之间要通信,他俩要定义一个接口,他们俩都是我hadoop项目组的类,定义的接口是我们俩都能使用这个接口
总结:不同进程之间的方法调用。