RMI(即Remote Method Invoke 远程方法调用)。在Java中,只要一个类extends了java.rmi.Remote接口,即可成为存在于服务器端的远程对象,供客户端访问并提供一定的服务。JavaDoc描述:Remote 接口用于标识其方法可以从非本地虚拟机上调用的接口。任何远程对象都必须直接或间接实现此接口。只有在“远程接口”(扩展 java.rmi.Remote 的接口)中指定的这些方法才可远程使用。 
 
注意:extends了Remote接口的类或者其他接口中的方法若是声明抛出了RemoteException异常,则表明该方法可被客户端远程访问调用。 
 
同时,远程对象必须实现java.rmi.server.UniCastRemoteObject类,这样才能保证客户端访问获得远程对象时,该远程对象将会把自身的一个拷贝以Socket的形式传输给客户端,此时客户端所获得的这个拷贝称为“存根”,而服务器端本身已存在的远程对象则称之为“骨架”。其实此时的存根是客户端的一个代理,用于与服务器端的通信,而骨架也可认为是服务器端的一个代理,用于接收客户端的请求之后调用远程方法来响应客户端的请求。 
 
RMI 框架的基本原理大概如下图,应用了代理模式来封装了本地存根与真实的远程对象进行通信的细节。
 
 
下面给出一个简单的RMI 应用,其中类图如下:其中IService接口用于声明服务器端必须提供的服务(即service()方法),ServiceImpl类是具体的服务实现类,而Server类是最终负责注册服务器远程对象,以便在服务器端存在骨架代理对象来对客户端的请求提供处理和响应。
 
 
各个类的源代码如下:
IService接口:
import java.rmi.Remote;
import java.rmi.RemoteException;
public interface IService extends Remote {
//声明服务器端必须提供的服务
String service(String content) throws RemoteException;
}

ServiceImpl实现类:

import java.rmi.RemoteException;
//UnicastRemoteObject用于导出的远程对象和获得与该远程对象通信的存根。
import java.rmi.server.UnicastRemoteObject; public class ServiceImpl extends UnicastRemoteObject implements IService { private String name; public ServiceImpl(String name) throws RemoteException {
this.name = name;
}
@Override
public String service(String content) {
return "server >> " + content;
}
}

Server类:

/*
* Context接口表示一个命名上下文,它由一组名称到对象的绑定组成。
* 它包含检查和更新这些绑定的一些方法。
*/
import javax.naming.Context;
/*
* InitialContext类是执行命名操作的初始上下文。
* 该初始上下文实现 Context 接口并提供解析名称的起始点。
*/
import javax.naming.InitialContext;
public class Server {
public static void main(String[] args) {
try {
//实例化实现了IService接口的远程服务ServiceImpl对象
IService service02 = new ServiceImpl("service02");
//初始化命名空间
Context namingContext = new InitialContext();
//将名称绑定到对象,即向命名空间注册已经实例化的远程服务对象
namingContext.rebind("rmi://localhost/service02", service02);
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("服务器向命名表注册了1个远程服务对象!");
}
}

Client类

import javax.naming.Context;
import javax.naming.InitialContext; public class Client {
public static void main(String[] args) {
String url = "rmi://localhost/";
try {
Context namingContext = new InitialContext();
// 检索指定的对象。 即找到服务器端相对应的服务对象存根
IService service02 = (IService) namingContext.lookup(url
+ "service02");
Class stubClass = service02.getClass();
System.out.println(service02 + " 是 " + stubClass.getName()
+ " 的实例!");
// 获得本底存根已实现的接口类型
Class[] interfaces = stubClass.getInterfaces();
for (Class c : interfaces) {
System.out.println("存根类实现了 " + c.getName() + " 接口!");
}
System.out.println(service02.service("你好!"));
} catch (Exception e) {
e.printStackTrace();
}
}
}
将以上代码保存于某一目录下,先运行“start rmiregistry”来启动JDK自带的注册表程序,它用于保存Server类注册的远程对象并允许远程客户端的请求访问;然后运行服务器端的Server类,即“start java Server”,该程序向注册表中注册具体的远程对象;最后才是运行客户端程序来查找并获得服务器端的远程对象存根,此时才能使用存根对象与服务器进行通信,命令是“java Client”。注意:上面命令中的start的功能是重新打开一个DOS窗口。
运行结果如下:

其实整个简单的RMI 应用中各个类的交互时序如下图:

本文出自 “蚂蚁” 博客,请务必保留此出处http://haolloyin.blog.51cto.com/1177454/332426

JavaRMI框架的更多相关文章

  1. RPC 框架 Dubbo 从理解到使用(一)

    技术架构演变 单一应用架构 通俗地讲,"单体应用(monolith application)"就是将应用程序的所有功能都打包成一个独立的单元.当网站流量很小时,只需一个应用,将所有 ...

  2. 避免重复造轮子的UI自动化测试框架开发

    一懒起来就好久没更新文章了,其实懒也还是因为忙,今年上半年的加班赶上了去年一年的加班,加班不息啊,好了吐槽完就写写一直打算继续的自动化开发 目前各种UI测试框架层出不穷,但是万变不离其宗,驱动PC浏览 ...

  3. ABP入门系列(1)——学习Abp框架之实操演练

    作为.Net工地搬砖长工一名,一直致力于挖坑(Bug)填坑(Debug),但技术却不见长进.也曾热情于新技术的学习,憧憬过成为技术大拿.从前端到后端,从bootstrap到javascript,从py ...

  4. 旺财速啃H5框架之Bootstrap(五)

    在上一篇<<旺财速啃H5框架之Bootstrap(四)>>做了基本的框架,<<旺财速啃H5框架之Bootstrap(二)>>篇里也大体认识了bootst ...

  5. Angular企业级开发(5)-项目框架搭建

    1.AngularJS Seed项目目录结构 AngularJS官方网站提供了一个angular-phonecat项目,另外一个就是Angular-Seed项目.所以大多数团队会基于Angular-S ...

  6. Scrapy框架爬虫初探——中关村在线手机参数数据爬取

    关于Scrapy如何安装部署的文章已经相当多了,但是网上实战的例子还不是很多,近来正好在学习该爬虫框架,就简单写了个Spider Demo来实践.作为硬件数码控,我选择了经常光顾的中关村在线的手机页面 ...

  7. 制作类似ThinkPHP框架中的PATHINFO模式功能

    一.PATHINFO功能简述 搞PHP的都知道ThinkPHP是一个免费开源的轻量级PHP框架,虽说轻量但它的功能却很强大.这也是我接触学习的第一个框架.TP框架中的URL默认模式即是PathInfo ...

  8. 旺财速啃H5框架之Bootstrap(四)

    上一篇<<旺财速啃H5框架之Bootstrap(三)>>已经把导航做了,接下来搭建内容框架.... 对于不规整的网页,要做成自适应就有点玩大了.... 例如下面这种版式的页面. ...

  9. 一起学 Java(三) 集合框架、数据结构、泛型

    一.Java 集合框架 集合框架是一个用来代表和操纵集合的统一架构.所有的集合框架都包含如下内容: 接口:是代表集合的抽象数据类型.接口允许集合独立操纵其代表的细节.在面向对象的语言,接口通常形成一个 ...

随机推荐

  1. 【BZOJ4671】 异或图

    Description 定义两个结点数相同的图 G1 与图 G2 的异或为一个新的图 G, 其中如果 (u, v) 在 G1 与 G2 中的出现次数之和为 1, 那么边 (u, v) 在 G 中, 否 ...

  2. websocket 连接测试端口服务是否正常代码

    <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...

  3. http状态码301和302详解及区别——辛酸的探索之路

    原文链接:https://blog.csdn.net/grandPang/article/details/47448395 一直对http状态码301和302的理解比较模糊,在遇到实际的问题和翻阅各种 ...

  4. Spring Cloud Feign声明式服务调用(转载)+遇到的问题

    转载:原文 总结: 1.pom添加依赖 2.application中填写正确的eureka配置 3.启动项中增加注解 @EnableFeignClients 4.填写正确的调用接口 通过原文使用Fei ...

  5. SpringMVC工作原理的介绍

    1.用户向服务器发送请求,请求被Spring前端控制Servlet DispatcherServlet捕获 2.DispatcherServlet对请求URL进行解析,得到请求资源标识符(URL).然 ...

  6. elasticsearch与kibana安装过程(linux)

    elasticsearch与kibana安装 下载 Elasticsearch 官网:https://www.elastic.co/,elastic search应用本质就是一个jvm进程,所以需要J ...

  7. [Ajax三级联动 无刷新]

    三级联动 的效果图 html页面: <body> <label class="fl">区域:</label> <select class= ...

  8. git分支名大小写问题导致分支push到远程失败

    windows系统不识别文件夹大小写导致 本地分支master, 在master上面新建一个分支Hotfix/aa 由于Hotfix首字母大写,所以windows系统会在 项目.git\refs\he ...

  9. 百度AI---语音识别

    题记:娱乐性的玩玩百度接口. 说实话,其接口个人觉得有点烂,重试了好几个音频文件才成功. 1.重新申请AppID.SecretKey .API Key. 链接:https://console.bce. ...

  10. 六十九:flask上下文之线程隔离的g对象的使用

    保存全局对象的g对象g对象是在整个flask应用运行期间都是可以使用的,并且也是和request一样,是线程隔离的,这个对象是专门用来存放开发者自己定义的一些数据,方便在整个flask程序中都可以使用 ...