今天在看代理设计模式,java中远程代理的实现一定会用到RMI的,很久没有温习过RMI的知识了,今天就重新过一遍这个知识点来让自己加深印象,构建一个简单的RMI小程序需要用到一下几个类:

  • java.rmi.Remote
  • java.rmi.RemoteException
  • java.rmi.Naming

UML类图:

类图很简单,但是有几点需要注意:

  • 服务器端的接口应该继承自java.rmi.server.UnicastRemoteObject类并实现java.rmi.Remote接口
  • 由于是远程方法调用,有可能由于网络原因而出现异常,服务器端接口的方法应该抛出java.rmi.RemoteException
  • 服务器端接口的具体实现类必须显示地声明一个无参构造方法并抛出RemoteException, 这是因为UnicastRemoteObject类的无参构造方法就抛出了RemoteException,这样在实例化MyRemoteImpl之前会先实例化UnicastRemoteObject
  • 由于参数和返回值需要在网络中传播,如果你的参数和返回值不是java原始数据类型(例如自定义的对象),那么该对象需要实现java.io.Serializable, 这样JVM才能对该对象进行序列及反序列化

我们再来看看具体的实现:

MyRemote接口

import java.rmi.Remote;
import java.rmi.RemoteException; public interface MyRemote extends Remote { public String getServerTime(String employee) throws RemoteException; }

MyRemoteImpl实现类

import java.rmi.Naming;
import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;
import java.util.Date; public class MyRemoteImpl extends UnicastRemoteObject implements MyRemote { private static final long serialVersionUID = 6812592847867041499L; public MyRemoteImpl() throws RemoteException {
super();
} public static void main(String[] args) throws MalformedURLException, RemoteException, AlreadyBoundException {
MyRemote myRemote = new MyRemoteImpl();
Naming.bind("rmi://192.168.3.4:1099/myRemote", myRemote);
System.out.println("Ready...");
} @Override
public String getServerTime(String employee) throws RemoteException {
return String.format("Hello %s, Italy time is: %s", employee, new Date());
} }

客户端测试类:

import java.net.MalformedURLException;
import java.rmi.Naming;
import java.rmi.NotBoundException;
import java.rmi.RemoteException; public class RmiClient { public static void main(String[] args) throws MalformedURLException, RemoteException, NotBoundException {
MyRemote myRemote = (MyRemote) Naming.lookup("rmi://192.168.3.4:1099/myRemote");
System.out.println(myRemote.getServerTime("Linda"));
} }

现在运行测试还为时尚早,为了实现跨JVM的远程方法调用我们还需要做一些必须的事情:

  • 使用rmic工具生成Stub桩供远程调用(Java 1.5之后可以不用生成这个文件?还在研究)
  • rmiregistry开放RMI注册
  • 使用java.rmi.Naming的bind方法来绑定服务

我们一步一步来:

首先生成stub文件,客户端需要这个文件来调用远程对象,这个文件其实就是远程对象在本地的一个代理,客户端以为是跟远程对象直接打交道,其实客户端调用的是该客户服务对象,该桩又调用远程对象。

生成的桩文件:

运行rmiregistry命令:

运行MyRemoteImpl的main方法来将服务绑定到远程计算机的1099端口

我们写的是一个RMI程序,为了测试跨内存空间(跨JVM)的远程方法调用,我把服务器端的以下class文件放到了国外服务器上面:

  • MyRemote.class
  • MyRemoteImpl.class
  • MyRemoteImpl_Stub.class

把以下客户端的class放到本地:

  • MyRemote.class
  • MyRemoteImpl_Stub.class
  • RmiClient.class

现在让我来测试一下,运行命令:

java RmiClient

从运行结果可以看出来,本地客户端成功调用到了远在欧洲的对象并把String值返回到了本地通过控制台打印出来。下一个待解决的问题是如何可以不需要stub文件来进行远程方法调用,正在学习中。

玩玩RMI的更多相关文章

  1. tomcat RMI 停不掉

    项目采用jfinal框架,做了一个RMI的服务,对其它程序提供服务.实现上,写了一个RmiPlugin package com.wisdombud.cloudtalk.plugin; import j ...

  2. Exception thrown by the agent : java.rmi.server.ExportException: Port already in use

    今天有个应用一直起不来,感觉配置都对啊,奇了怪了.看日志发现如下: STATUS | wrapper | 2017/01/04 08:09:31 | Launching a JVM...INFO | ...

  3. RMI(远程接口调用)

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

  4. Java RMI之HelloWorld篇

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

  5. Spring远程调用技术<1>-RMI

    在java中,我们有多种可以使用的远程调用技术 1.远程方法调用(remote method invocation, RMI)  适用场景:不考虑网络限制时(例如防火墙),访问/发布基于java的服务 ...

  6. Java的RMI远程方法调用实现和应用

    最近在学习Dubbo,RMI是很重要的底层机制,RMI(Remote Method Invocation)远程方法调用是一种计算机之间利用远程对象互相调用实现双方通讯的一种通讯机制.使用这种机制,某一 ...

  7. Java远程方法调用(Remote Method Invocation,RMI)

    Java RMI简介: 它是Java的一个核心API和类库,允许一个Java虚拟机上运行的Java程序调用不同虚拟机上运行的对象中的方法,即使这两个虚拟机运行于物理隔离的不同主机上. Java RMI ...

  8. 启动tomcat时 错误: 代理抛出异常 : java.rmi.server.ExportException: Port already in use: 1099;

     错误: 代理抛出异常 : java.rmi.server.ExportException: Port already in use: 1099; nested exception is:  java ...

  9. JAVA RMI 实例

    下面我将介绍一个完整的实例,让初学者能快速体验RMI的功用. 分为以下四个步骤 1. 创建远程接口及声明远程方法(HelloInterface.java)2. 实现远程接口及远程方法(继承Unicas ...

随机推荐

  1. console.dir()和console.log()的区别

    console.log()可以取代alert()或document.write(),在网页脚本中使用console.log(data)时,会在控制台打印出数据. console.dir()可以显示一个 ...

  2. 【原生js】原生js实现验证码短信发送倒计时

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  3. 坚持使用GNU/Linux

    在Windows或Mac OS X下,包括手机上的iOS与Android,应用程序开发得越来越复杂.点下一个按钮,光标转半天,程序在背后做了一堆你不清楚的操作.这不仅仅让你花更 长且不确定的时间等待, ...

  4. 在vim编辑器中,删除操作

    我这里在编辑一个很大的文件,有几万行,都是文件名sheetid, 中间有很多空行,我现在要做的事情就有要把这个文件中的空行都删除掉,这个本来想在ultraedit里面完成的,结果弄了好半天都没有搞定, ...

  5. Beego学习笔记——开始

    beego简介 beego是一个快速开发Go应用的http框架,他可以用来快速开发API.Web.后端服务等各种应用,是一个RESTFul的框架,主要设计灵感来源于tornado.sinatra.fl ...

  6. Qt 解压/压缩文件

    很久没有在博客园写随笔了,今天项目需要解压和压缩文件,所以去了解哈. 参考的是大神的代码:https://yq.aliyun.com/articles/24428. 使用的是 QuaZIP类. 类 说 ...

  7. Pass和ClassPath变量配置

    1.pass环境变量配置的是可执行性文件bin目录,是为了在任意盘符下都可以运行javac.exe和java.exe所配置的. 2.classpath环境变量记录的是java类运行文件所在的目录,一般 ...

  8. jquery轻松实现li标签上下滚动的原理

    在网站上我们常看到有滚动的文字或者图片,比如消息提醒,新闻列表,等等.那么这些效果是怎么形成的呢?经过查阅,找到一种十分方便的写法,经过改良,得出我自己的终极版滚动效果. 我先写个布局吧 <di ...

  9. 浙大pat1013题解

    1013. Battle Over Cities (25) 时间限制 400 ms 内存限制 32000 kB 代码长度限制 16000 B 判题程序 Standard 作者 CHEN, Yue It ...

  10. MySQL数据库安装(CentOS操作系统/tar.gz方式)

    1. 上传Mysql安装包“mysql-5.5.40-linux2.6-x86_64.tar.gz”到部署机,位置任意: 2. 将Mysql安装包解压到其所在目录,命令如下: -linux2.-x86 ...