侯体宗的博客
  • 首页
  • Hyperf版
  • beego仿版
  • 人生(杂谈)
  • 技术
  • 关于我
  • 更多分类
    • 文件下载
    • 文字修仙
    • 中国象棋ai
    • 群聊
    • 九宫格抽奖
    • 拼图
    • 消消乐
    • 相册

Java RMI图文详解(附示例)

Java  /  管理员 发布于 8年前   305

Java RMI:Java远程方法调用,即Java RMI(Java Remote Method Invocation)是Java编程语言里,一种用于实现远程过程调用的应用程序编程接口。

它使客户机上运行的程序可以调用远程服务器上的对象。远程方法调用特性使Java编程人员能够在网络环境中分布操作。RMI全部的宗旨就是尽可能简化远程接口对象的使用。

我们知道远程过程调用(Remote Procedure Call, RPC)可以用于一个进程调用另一个进程(很可能在另一个远程主机上)中的过程,从而提供了过程的分布能力。Java 的 RMI 则在 RPC 的基础上向前又迈进了一步,即提供分布式对象间的通讯。

RMI(Remote Method Invocation)为远程方法调用,是允许运行在一个Java虚拟机的对象调用运行在另一个Java虚拟机上的对象的方法。

这两个虚拟机可以是运行在相同计算机上的不同进程中,也可以是运行在网络上的不同计算机中。

【JavaRMI】

一、工作原理

RMI能让一个Java程序去调用网络中另一台计算机的Java对象的方法,那么调用的效果就像是在本机上调用一样。通俗的讲:A机器上面有一个class,通过远程调用,B机器调用这个class 中的方法。

RMI,远程方法调用(Remote Method Invocation)是Enterprise JavaBeans的支柱,是建立分布式Java应用程序的方便途径。RMI是非常容易使用的,但是它非常的强大。

RMI的基础是接口,RMI构架基于一个重要的原理:定义接口和定义接口的具体实现是分开的。下面我们通过具体的例子,建立一个简单的远程计算服务和使用它的客户程序

二、RMI包含部分:

1、远程服务的接口定义

2、远程服务接口的具体实现

3、桩(Stub)和框架(Skeleton)文件

4、一个运行远程服务的服务器

5、一个RMI命名服务,它允许客户端去发现这个远程服务

6、类文件的提供者(一个HTTP或者FTP服务器)

7、一个需要这个远程服务的客户端程序

三、RMI的用途?

RMI的用途是为分布式Java应用程序之间的远程通信提供服务,提供分布式服务。

目前主要应用时封装在各个J2EE项目框架中,例如Spring,EJB(Spring和EJB均封装了RMI技术)

在Spring中实现RMI:

①在服务器端定义服务的接口,定义特定的类实现这些接口;

②在服务器端使用org.springframework.remoting.rmi.RmiServiceExporter类来注册服务;

③在客户端使用org.springframework.remoting.rmi.RmiProxyFactoryBean来实现远程服务的代理功能;

④在客户端定义访问与服务器端服务接口相同的类

四、RMI的局限?

RMI目前使用Java远程消息交换协议JRMP(Java Remote Messaging Protocol)进行通信。JRMP是专为Java的远程对象制定的协议,由于JRMP是专为Java对象制定的,因此,RMI对于用非Java语言开发的应用系统的支持不足。

不能与用非Java语言书写的对象进行通信(意思是只支持客户端和服务器端都是Java程序的代码的远程调用)。

五、RMI的使用局限?

由于客户机和服务器都是使用Java编写的,二者平台兼容性的要求仅仅是双方都运行在版本兼容的Java虚拟机上。

六、RMI调用远程方法的参数和返回值

当调用远程对象上的方法时,客户机除了可以将原始类型的数据作为参数一外,还可以将对象作为参数来传递,与之相对应的是返回值,可以返回原始类型或对象,这些都是通过Java的对象序列化(serialization)技术来实现的。(换而言之:参数或者返回值如果是对象的话必须实现Serializable接口)

七、 RMI应用程序的基本模型

1.jpg

八、RMI体系结构

2.jpg

桩/框架(Stub/Skeleton)层:客户端的桩和服务器端的框架;

远程引用(remote reference)层:处理远程引用行为

传送层(transport):连接的建立和管理,以及远程对象的跟踪

九、 RMI类和接口(完成一个简单RMI需要用到的类)。

3.jpg

(一) Remote接口:是一个不定义方法的标记接口

Public interface Remote{}

在RMI中,远程接口声明了可以从远程Java虚拟机中调用的方法集。远程接口满足下列要求:

1、远程接口必须直接或间接扩展Java.rmi.Remote接口,且必须声明为public,除非客户端于远程接口在同一包中

2、在远程接口中的方法在声明时,除了要抛出与应用程序有关的一场之外,还必须包括RemoteException(或它的超类,IOExcepion或Exception)异常

3、在远程方法声明中,作为参数或返回值声明的远程对象必须声明为远程接口,而非该接口的实现类。

(二) RemoteObject抽象类实现了Remote接口和序列化Serializable接口,它和它的子类提供RMI服务器函数。

(三) LocateRegistry final()类用于获得特定主机的引导远程对象注册服务器程序的引用(即创建stub),或者创建能在特定端口接收调用的远程对象注册服务程序。

服务器端:向其他客户机提供远程对象服务

SomeService servcie=……;//远程对象服务

1、Registry registry=LocateRegisty.getRegistry();//Registry是个接口,他继承了Remote,此方法返回本地主机在默认注册表端口 1099 上对远程对象 Registry 的引用。

2、getRegistry(int port) 返回本地主机在指定 port 上对远程对象 Registry 的引用;

3、getRegistry(String host) 返回指定 host 在默认注册表端口 1099 上对远程对象 Registry 的引用;

4、getRegistry(String host, int port) 返回指定的 host 和 port 上对远程对象 Registry 的引用

5、registry.bind(“I serve”,service);// bind(String name,Remote obj) 绑定对此注册表中指定 name 的远程引用。name : 与该远程引用相关的名称 obj : 对远程对象(通常是一个 stub)的引用

6、unbind(String name)移除注册表中指定name的绑定。

7、rebind(String name,Remote obj)重新绑定,如果name已存在,但是Remote不一样则替换,如果Remote一样则丢弃现有的绑定

8、lookup(String name) 返回注册表中绑定到指定 name 的远程引用,返回Remote

9、String[] list() 返回在此注册表中绑定的名称的数组。该数组将包含一个此注册表中调用此方法时绑定的名称快照。

客户机端:向服务器提供相应的服务请求。

Registry registry=LocateRegisty.getRegistry();
SomeService servcie=(SomeService)registry.lookup(“I serve”);
Servcie.requestService();

(四) Naming类和Registry类类似。

客户端:

Naming.lookup(String url)url 格式如下"rmi://localhost/"+远程对象引用

服务器端:

Registry registry=LocateRegistry.createRegistry(int port);Naming.rebind(“service”,service);

(五) RMISecurityManager类

在RMI引用程序中,如果没有设置安全管理器,则只能从本地类路径加载stub和类,这可以确保应用程序不受由远程方法调用所下载的代码侵害

在从远程主机下载代码之前必须执行以下代码来安装RMISecurityManager:

System.setSecurityManager(new RMISecurityManager());

十、demo开发

为了编写一个demo,我们分为两部分,一部分是server端的代码,一部分是client端的代码,client端的代码主要是为了使用server端的代码。当然这个代码是非常简单的,只是为了说明问题,现实的使用会使比较复杂的。

(一) 我们的目的

建立一个server端的java project,包含远程端的代码,定义接口,定义接口实现,然后在建立一个client端的java project,通过RMI使用远端服务中的方法。

(二) 我们的代码结构

4.jpg

(三) 远程服务代码

1. 远程服务的接口定义

第一步就是建立和编译服务接口的Java代码。这个接口定义了所有的提供远程服务的功能,下面是源程序:

UserManagerInterface.java

package cn.com.tt.rmiserver.stub;import java.rmi.Remote;import java.rmi.RemoteException;import cn.com.tt.rmiserver.bean.Account;public interface UserManagerInterface extends Remote{    public String getUserName() throws RemoteException;    public Account getAdminAccount() throws RemoteException;}

接口必须继承Remote类,每一个定义地方法都要抛出RemoteException异常对象。

2. 接口的具体实现

第二步就是对于上面的接口进行实现:

UserManagerImp.java

package cn.com.tt.rmiserver;import java.rmi.RemoteException;import cn.com.tt.rmiserver.stub.UserManagerInterface;import cn.com.tt.rmiserver.bean.Account;public class UserManagerImp implements UserManagerInterface {    public UserManagerImp() throws RemoteException {    }    private static final long serialVersionUID = -3111492742628447261L;    public String getUserName() throws RemoteException{        return "TT";    }    public Account getAdminAccount() throws RemoteException{        Account account=new Account();        account.setUsername("TT");        account.setPassword("123456");        return account;    }}

3. 定义一个bean,实现implements Serializable序列化接口。也就是可以在client和server端进行传输的可序列化对象。

Account.java

package cn.com.tt.rmiserver.bean;import java.io.Serializable;public class Account implements Serializable,Cloneable{    private static final long serialVersionUID = -1858518369668584532L;    private String username;    private String password;        public String getUsername() {        return username;    }    public void setUsername(String username) {        this.username = username;    }    public String getPassword() {        return password;    }    public void setPassword(String password) {        this.password = password;    }}

4. 定义server端的主程序入口。

Entry.java

package cn.com.tt.rmiserver.entry;import java.rmi.AlreadyBoundException;import java.rmi.RemoteException;import java.rmi.registry.LocateRegistry;import java.rmi.registry.Registry;import java.rmi.server.UnicastRemoteObject;import cn.com.tt.rmiserver.UserManagerImp;import cn.com.tt.rmiserver.stub.UserManagerInterface;public class Entry {    public static void main(String []args) throws AlreadyBoundException, RemoteException{        UserManagerImp userManager=new UserManagerImp();        UserManagerInterface userManagerI=(UserManagerInterface)UnicastRemoteObject.exportObject(userManager,0);        // Bind the remote object's stub in the registry        Registry registry = LocateRegistry.createRegistry(2002);   registry.rebind("userManager", userManagerI);        System.out.println("server is ready");        }}

(四) client端代码

1、把Server端的Account类和接口UserManagerInterface 导出Export成jar包,命名为:RmiServerInterface.jar。导入到client中。

2、项目——右键——Export——java——jar file——next——选择Account类和接口UserManagerInterface——命名为:RmiServerInterface.jar如下图:

5.jpg

3. 新建一个java Project,导入jar包,编写客户端代码。

4. 代码

ClientEntry.java

package weiblog.rmi;import java.rmi.NotBoundException;import java.rmi.RemoteException;import java.rmi.registry.LocateRegistry;import java.rmi.registry.Registry;import cn.com.tt.rmiserver.stub.UserManagerInterface;public class ClientEntry {        public static void main(String []args){    try {Registry registry = LocateRegistry.getRegistry("localhost",2004);UserManagerInterface userManager = (UserManagerInterface)registry.lookup("userManager");System.out.println("用户名是"+userManager.getAdminAccount().getUsername()        +"密码"+userManager.getAdminAccount().getPassword());        } catch (RemoteException e) {// TODO Auto-generated catch blocke.printStackTrace();        } catch (NotBoundException e) {// TODO Auto-generated catch blocke.printStackTrace();        }}}

5. 先运行服务器端代码, 然后运行客户端代码,就会显示运行结果,客户端可以运行多次,每次都可以取得服务器端的对象。如果要再次运行客户端代码就需要更改端口号,如果不更改就会显示端口号被占用。

更多java知识请关注java基础教程栏目。

以上就是Java RMI图文详解(附示例)的详细内容,更多请关注其它相关文章!


  • 上一条:
    java中comparable和comparator的区别
    下一条:
    java中Byte与byte的区别是什么?
  • 昵称:

    邮箱:

    0条评论 (评论内容有缓存机制,请悉知!)
    最新最热
    • 分类目录
    • 人生(杂谈)
    • 技术
    • linux
    • Java
    • php
    • 框架(架构)
    • 前端
    • ThinkPHP
    • 数据库
    • 微信(小程序)
    • Laravel
    • Redis
    • Docker
    • Go
    • swoole
    • Windows
    • Python
    • 苹果(mac/ios)
    • 相关文章
    • 在java中实现的脱敏工具类代码示例分享(0个评论)
    • zookeeper安装流程步骤(0个评论)
    • 在java中你背的“八股文”可能已经过时了(2个评论)
    • 在php8.0+版本中使用属性来增加值代码示例(3个评论)
    • java 正则表达式基础,实例学习资料收集大全 原创(0个评论)
    • 近期文章
    • 在go语言中使用api.geonames.org接口实现根据国际邮政编码获取地址信息功能(1个评论)
    • 在go语言中使用github.com/signintech/gopdf实现生成pdf分页文件功能(0个评论)
    • gmail发邮件报错:534 5.7.9 Application-specific password required...解决方案(0个评论)
    • 欧盟关于强迫劳动的规定的官方举报渠道及官方举报网站(0个评论)
    • 在go语言中使用github.com/signintech/gopdf实现生成pdf文件功能(0个评论)
    • Laravel从Accel获得5700万美元A轮融资(0个评论)
    • 在go + gin中gorm实现指定搜索/区间搜索分页列表功能接口实例(0个评论)
    • 在go语言中实现IP/CIDR的ip和netmask互转及IP段形式互转及ip是否存在IP/CIDR(0个评论)
    • PHP 8.4 Alpha 1现已发布!(0个评论)
    • Laravel 11.15版本发布 - Eloquent Builder中添加的泛型(0个评论)
    • 近期评论
    • 122 在

      学历:一种延缓就业设计,生活需求下的权衡之选中评论 工作几年后,报名考研了,到现在还没认真学习备考,迷茫中。作为一名北漂互联网打工人..
    • 123 在

      Clash for Windows作者删库跑路了,github已404中评论 按理说只要你在国内,所有的流量进出都在监控范围内,不管你怎么隐藏也没用,想搞你分..
    • 原梓番博客 在

      在Laravel框架中使用模型Model分表最简单的方法中评论 好久好久都没看友情链接申请了,今天刚看,已经添加。..
    • 博主 在

      佛跳墙vpn软件不会用?上不了网?佛跳墙vpn常见问题以及解决办法中评论 @1111老铁这个不行了,可以看看近期评论的其他文章..
    • 1111 在

      佛跳墙vpn软件不会用?上不了网?佛跳墙vpn常见问题以及解决办法中评论 网站不能打开,博主百忙中能否发个APP下载链接,佛跳墙或极光..
    • 2016-11
    • 2018-03
    • 2020-03
    • 2023-05
    • 2023-11
    • 2024-01
    Top

    Copyright·© 2019 侯体宗版权所有· 粤ICP备20027696号 PHP交流群

    侯体宗的博客