1.背景

在学习代理模式的过程中接触到了远程调用,jdk有自己的RMI实现,所以这边自己实现了RMI远程调用,并记录下心得.

感受最深的是RMI和现在的微服务有点相似,都是通过"注册中心"来获取数据,比如spring cloud 中通过feign来获取数据,这个就可以看作一个代理模式,我们通过feigh获取数据其实是通过别的服务器上的代码来获取数据的,而RMI中是通过rmiRegistry注册中心来注册,并且通过

  1. Naming.lookup("rmi://127.0.0.1/RemoteHello")

这个方法来获取数据.      其实本质都差不多,spring cloud 数据传输格式主要是 json, 而 RMI主要是二进制,因为要传输的对象都实现了Serializable接口. 可能RMI在分布式这边用的多一些吧,但是我没有接触过,还不清楚.

2.代码实现

这边有点坑,因为一直用eclipse编译代码,都忘记了cmd命令行怎么编译了,结果被包名给搞糊涂了,这边记录总结下,希望有人碰到这个问题不要在纠结太久.

我们先定义自己的远程接口MyRemote

  1. package state.remote;
  2.  
  3. import java.rmi.Remote;
  4. import java.rmi.RemoteException;
  5.  
  6. public interface MyRemote extends Remote {
  7. public String sayHello() throws RemoteException;
  8. }

这边定义了一个方法,返回String,String已经实现了Serializable接口,所以我们可以直接使用.  请注意上面的包名: package state.remote

定义实现类

  1. package state.remote;
  2.  
  3. import java.net.MalformedURLException;
  4. import java.rmi.Naming;
  5. import java.rmi.RemoteException;
  6. import java.rmi.server.UnicastRemoteObject;
  7.  
  8. public class MyRemoteImpl extends UnicastRemoteObject implements MyRemote{
  9.  
  10. /**
  11. *
  12. */
  13. private static final long serialVersionUID = 927479549518191259L;
  14.  
  15. protected MyRemoteImpl() throws RemoteException {
  16. }
  17.  
  18. public static void main(String[] args) {
  19. try {
  20. MyRemote service = new MyRemoteImpl();
  21. //注册
  22. Naming.rebind("RemoteHello", service);
  23. } catch (RemoteException e) {
  24. e.printStackTrace();
  25. } catch (MalformedURLException e) {
  26. e.printStackTrace();
  27. }
  28. }
  29.  
  30. @Override
  31. public String sayHello() throws RemoteException {
  32. return "Hello";
  33. }
  34. }

通过Naming的rebind方法我们可以把RemoteHello注册到服务上.  还是注意报名:package state.remote

定义客户端

  1. package state.remote;
  2.  
  3. import java.net.MalformedURLException;
  4. import java.rmi.Naming;
  5. import java.rmi.NotBoundException;
  6. import java.rmi.RemoteException;
  7.  
  8. public class MyRemoteClient {
  9. public static void main(String[] args) {
  10. new MyRemoteClient().go();
  11. }
  12.  
  13. public void go() {
  14. try {
  15. MyRemote service = (MyRemote) Naming.lookup("rmi://127.0.0.1/RemoteHello");
  16. String s = service.sayHello();
  17. System.out.println(s);
  18. } catch (MalformedURLException | RemoteException | NotBoundException e) {
  19. e.printStackTrace();
  20. }
  21. }
  22. }

客户端通过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 远程调用的更多相关文章

  1. Java RMI 远程方法调用

    Java RMI 指的是远程方法调用 (Remote Method Invocation).它是一种机制,能够让在某个 Java 虚拟机上的对象调用另一个 Java 虚拟机中的对象上的方法.可以用此方 ...

  2. Java RMI远程方法调用

    RMI(远程接口调用) 1. RMI的原理: RMI系统结构,在客户端和服务器端都有几层结构. 方法调用从客户对象经占位程序(Stub).远程引用层(Remote Reference Layer)和传 ...

  3. Java中RMI远程调用demo

    Java远程方法调用,即Java RMI(Java Remote Method Invocation),一种用于实现远程过程调用的应用程序编程接口.它使客户机上运行的程序可以调用远程服务器上的对象.远 ...

  4. java项目中rmi远程调用实例

    1.创建一个学生实体类Student.java: package com.RMIdemo.entity; @SuppressWarnings("serial") public cl ...

  5. WebService与RMI(远程调用方式实现系统间通信)

    前言 本文是<分布式java应用基础与实践>读书笔记:另外参考了此博客,感觉讲的挺好的,尤其是其中如下内容: 另外,消息方式实现系统间通信本文不涉及.RMI则只采用spring RMI框架 ...

  6. Java 常用远程调用协议比较

    一.综述本文比较了RMI,Hessian,Burlap,Httpinvoker,web service等5种通讯协议的在不同的数据结构和不同数据量时的传输性能.RMI是java语言本身提供的远程通讯协 ...

  7. hession RMI 远程调用

    /** * * @author administror * 在java中,需要去extends 继承java.rmi.Remote 接口,才能称为在于服务器流的远程对象. * 各客服端调用 * */p ...

  8. cas的http配置和rmi远程调用

    1.cas配置http请求(服务端) 1) 解压cas-server-3.4.4-release.zip将modules目录下的cas-server-webapp-3.4.4.war改名称为cas.w ...

  9. Spring HttpIvoker实现Java的远程调用

    Spring HttpInvoker一种JAVA远程方法调用框架实现,使用的是HTTP协议,允许穿透防火墙,使用JAVA系列化方式,但仅限于Spring应用之间使用,即调用者与被调用者都必须是使用Sp ...

随机推荐

  1. STM32 GPIO相关

    1. STM32 的 IO 作为输入的时候,可以程序设置上下拉电阻(可以不用外接上下拉电阻). 2.GPIO有四种输入模式:浮空输入.上拉输入.下拉输入.模拟输入: 3.GPIO有四种输出模式:开漏输 ...

  2. 02MySQL数据库

    1.MySQL启动和关闭 2.登录MySQL数据库 MySQL是一个需要账户名密码登录的数据库,登陆后使用,它提供了一个默认的root账号,使用安装时设置的密码即可登录. 格式1:cmd>  m ...

  3. libboost_regex 备份用时

    libboost_regex-vc100-mt-s-1_57.lib  //生成数据

  4. Python核心技术与实战——三|字符串

    一.字符串基础 Python的字符串支持单引号('').双引号("")和三引号之中('''....'''和"""...""&quo ...

  5. linux 时区问题

    1.java项目发现 服务器时间不正确,修改了服务器时间之后依然没解决. 2.java虚拟机的时区也需要设置:

  6. git概述(二)

    分支管理 分支在实际中有什么用呢?假设你准备开发一个新功能,但是需要两周才能完成,第一周你写了50%的代码,如果立刻提交,由于代码还没写完,不完整的代码库会导致别人不能干活了.如果等代码全部写完再一次 ...

  7. C++ GUI Qt4学习笔记03

    C++ GUI Qt4学习笔记03   qtc++spreadsheet文档工具resources 本章介绍创建Spreadsheet应用程序的主窗口 1.子类化QMainWindow 通过子类化QM ...

  8. 049:ORM常用Field详解(1)

    常用字段: 在 Django 中,定义了一些 Field 来与数据库表中的字段类型来进行映射.以下将介绍那些常用的字段类型. AutoField: 映射到数据库中是 int 类型,可以有自动增长的特性 ...

  9. 弹性盒子FlexBox简介(二)

    弹性盒子属性 一.align-content属性 属性作用:用于修改flex-wrap属性行为.类似于justify-content,但它不是设置弹性子元素的对齐,而是设置各个行的对齐. 属性值: f ...

  10. SQL SERVER 数据库如何限制一列不能重复(已经有主键)

    ALTER TABLE 表名ADDCONSTRAINT 约束名 UNIQUE (列名) -------------------------------------------------------- ...