1.背景
在学习代理模式的过程中接触到了远程调用,jdk有自己的RMI实现,所以这边自己实现了RMI远程调用,并记录下心得.
感受最深的是RMI和现在的微服务有点相似,都是通过"注册中心"来获取数据,比如spring cloud 中通过feign来获取数据,这个就可以看作一个代理模式,我们通过feigh获取数据其实是通过别的服务器上的代码来获取数据的,而RMI中是通过rmiRegistry注册中心来注册,并且通过
Naming.lookup("rmi://127.0.0.1/RemoteHello")
这个方法来获取数据. 其实本质都差不多,spring cloud 数据传输格式主要是 json, 而 RMI主要是二进制,因为要传输的对象都实现了Serializable接口. 可能RMI在分布式这边用的多一些吧,但是我没有接触过,还不清楚.
2.代码实现
这边有点坑,因为一直用eclipse编译代码,都忘记了cmd命令行怎么编译了,结果被包名给搞糊涂了,这边记录总结下,希望有人碰到这个问题不要在纠结太久.
我们先定义自己的远程接口MyRemote
package state.remote; import java.rmi.Remote;
import java.rmi.RemoteException; public interface MyRemote extends Remote {
public String sayHello() throws RemoteException;
}
这边定义了一个方法,返回String,String已经实现了Serializable接口,所以我们可以直接使用. 请注意上面的包名: package state.remote
定义实现类
package state.remote; import java.net.MalformedURLException;
import java.rmi.Naming;
import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject; public class MyRemoteImpl extends UnicastRemoteObject implements MyRemote{ /**
*
*/
private static final long serialVersionUID = 927479549518191259L; protected MyRemoteImpl() throws RemoteException {
} public static void main(String[] args) {
try {
MyRemote service = new MyRemoteImpl();
//注册
Naming.rebind("RemoteHello", service);
} catch (RemoteException e) {
e.printStackTrace();
} catch (MalformedURLException e) {
e.printStackTrace();
}
} @Override
public String sayHello() throws RemoteException {
return "Hello";
}
}
通过Naming的rebind方法我们可以把RemoteHello注册到服务上. 还是注意报名:package state.remote
定义客户端
package state.remote; import java.net.MalformedURLException;
import java.rmi.Naming;
import java.rmi.NotBoundException;
import java.rmi.RemoteException; public class MyRemoteClient {
public static void main(String[] args) {
new MyRemoteClient().go();
} public void go() {
try {
MyRemote service = (MyRemote) Naming.lookup("rmi://127.0.0.1/RemoteHello");
String s = service.sayHello();
System.out.println(s);
} catch (MalformedURLException | RemoteException | NotBoundException e) {
e.printStackTrace();
}
}
}
客户端通过Naming的lookup方法可以获取数据.
接下来我们就进入坑吧
坑1.
我们进入到目录
打开windows特有的power shell 进行编译,power shell 我觉得最大的好处就是不用cd进入目录了
ok,第一个坑来了
MyRemoteImpl.java:24: 错误: 找不到符号
MyRemoteImpl.java:36: 错误: 方法不会覆盖或实现超类型的方法
这两个方法都是因为实现了接口,没有和接口一起编译所以报错,我们以前写的helloworld根本没有接口一说,只是 System.out.println("HelloWorld"),所以根本发现不了这个错误.
解决:
和接口一起编译
出现.class文件了
或者
javac *.java
也可以,直接把当前目录所有.java文件编译
ok,我们有.class文件了,可以用jdk的rmi生成stub文件了吧,(注意:stub文件相当于本地的远程调用接口,属于rmi的概念,这边以后有机会在写)
error: File .\MyRemoteImpl.class does not contain type MyRemoteImpl as expected, but type state.remote.MyRemoteImpl. Please remove the file, or make sure it appears in the correct subdirectory of the class path.
error: 找不到类MyRemoteImpl。
又进入了第二个坑
坑 2.
还记得上面的package 包名吗,因为rmic 在编译.class文件的时候需要识别包名,所以我们只能 javac state.remote.MyRemoteImpl用来实现, 要和上面的package一致.
我们来尝试下
ok,坑3
我们来到坑3了
说找不到这个类,很简单,因为需要在这个目录下在创建文件夹,谁让 package 包名是这样写的
在这个目录下创建,
再在state目录下创建
,
然后我们进入remote目录,把这两个文件方法到这里.,
在执行rmic命令,
ok没有报错,这里说骨架不在必要,因为整合到了server中,ok,多了MyRemoteImpl_Stub.class,我们的客户就是通过这个访问远程虚拟机上的数据.
既然MyRemoteImpl_Stub.class在这个目录,我们就在这里注册服务吧
rmiregistry生成一个注册中心,然后运行 javac MyRemoteImpl 执行之前写的 rebind方法
好,只是一个远程调用这么多坑,第4个坑了,这边还是相同的错误,因为 package 之前写的是 state.remote,所以我们必须在这个目录下才能执行.class文件.
我们回到之前最开始的地方
注册中心
执行 rebind代码
可以了,rmiregistry必须和 java state.remoteMyRemoteImpl在同一个目录运行,因为rmiregistry会从classpath中的 .; 也就是当前目录寻找 _Stub结尾的文件,所以我们需要在同一个目录运行.或者把classpath设置要运行的rmiregisry目录也可以.
准备工作做好了,注册中心启动了.也注册了方法"RemoteHello",我们执行客户端
还是一样的错误....
我们需要编译MyRemoteClient,并把生成好的.class文件放到
_Stub目录下
执行
历尽千辛万苦,终于得到我们想要的结果了.
不容易.
3.总结
一句话:用eclipse编写代码真幸福.
(最需要注意的就是package 这个问题,如果只是测试的话不需要保留package,或者直接默认路径就可以,如果要保留package的话一定要设置好目录,因为 javac rmic 需要注意路径问题.)
java RMI 远程调用的更多相关文章
-
Java RMI 远程方法调用
Java RMI 指的是远程方法调用 (Remote Method Invocation).它是一种机制,能够让在某个 Java 虚拟机上的对象调用另一个 Java 虚拟机中的对象上的方法.可以用此方 ...
-
Java RMI远程方法调用
RMI(远程接口调用) 1. RMI的原理: RMI系统结构,在客户端和服务器端都有几层结构. 方法调用从客户对象经占位程序(Stub).远程引用层(Remote Reference Layer)和传 ...
-
Java中RMI远程调用demo
Java远程方法调用,即Java RMI(Java Remote Method Invocation),一种用于实现远程过程调用的应用程序编程接口.它使客户机上运行的程序可以调用远程服务器上的对象.远 ...
-
java项目中rmi远程调用实例
1.创建一个学生实体类Student.java: package com.RMIdemo.entity; @SuppressWarnings("serial") public cl ...
-
WebService与RMI(远程调用方式实现系统间通信)
前言 本文是<分布式java应用基础与实践>读书笔记:另外参考了此博客,感觉讲的挺好的,尤其是其中如下内容: 另外,消息方式实现系统间通信本文不涉及.RMI则只采用spring RMI框架 ...
-
Java 常用远程调用协议比较
一.综述本文比较了RMI,Hessian,Burlap,Httpinvoker,web service等5种通讯协议的在不同的数据结构和不同数据量时的传输性能.RMI是java语言本身提供的远程通讯协 ...
-
hession RMI 远程调用
/** * * @author administror * 在java中,需要去extends 继承java.rmi.Remote 接口,才能称为在于服务器流的远程对象. * 各客服端调用 * */p ...
-
cas的http配置和rmi远程调用
1.cas配置http请求(服务端) 1) 解压cas-server-3.4.4-release.zip将modules目录下的cas-server-webapp-3.4.4.war改名称为cas.w ...
-
Spring HttpIvoker实现Java的远程调用
Spring HttpInvoker一种JAVA远程方法调用框架实现,使用的是HTTP协议,允许穿透防火墙,使用JAVA系列化方式,但仅限于Spring应用之间使用,即调用者与被调用者都必须是使用Sp ...
随机推荐
-
android 入门-微博分享
[2015-03-11 13:40:32 - WeiboSDK] Unable to resolve target 'android-8' 修改project.properties target=a ...
-
超实用的JavaScript代码段 --倒计时效果
现今团购网.电商网.门户网等,常使用时间记录重要的时刻,如时间显示.倒计时差.限时抢购等,本文分析不同倒计时效果的计算思路及方法,掌握日期对象Date,获取时间的方法,计算时差的方法,实现不同的倒时计 ...
-
VB.NET 小程序 2
Public Class Form1 Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click ...
-
[大牛翻译系列]Hadoop(14)MapReduce 性能调优:减小数据倾斜的性能损失
6.4.4 减小数据倾斜的性能损失 数据倾斜是数据中的常见情况.数据中不可避免地会出现离群值(outlier),并导致数据倾斜.这些离群值会显著地拖慢MapReduce的执行.常见的数据倾斜有以下几类 ...
-
MultiCardMenu
https://github.com/wujingchao/MultiCardMenu MultiCardMenu-master.zip
-
阅读《RobHess的SIFT源码分析:综述》笔记
今天总算是机缘巧合的找到了照样一篇纲要性质的文章. 如是能早一些找到就好了.不过“在你认为为时已晚的时候,其实还为时未晚”倒是也能聊以自慰,不过不能经常这样迷惑自己,毕竟我需要开始跑了! 就照着这个大 ...
-
Junit 源码剖析(一)
采用Junit4.8.2分析Junit实现架构 源码架构两个大包:junit包 org包 首先分析org.junit.runners.model包下的几个类 org.junit.runners.mod ...
-
找到程序真正的入口(使用IDE追踪)
一.程序的真正入口 main或WinMain只是“语法规定的程序入口” 并不是“应用程序入口”. 我们使用VC++ 6.0 的栈回溯功能,找到main函数之前的代码.菜单View -> Debu ...
-
vbs和qtp一些脚本
********************************************************************************************** 用vbs调 ...
-
HIbernate实体类注解配置
一.类级别注解 1.@Entity(name="EntityName") 必须 name为可选,对应数据库中一的个表 2.@Table(name="",cata ...