文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

Java 中 RMI 的使用

2024-12-03 05:44

关注

RMI 介绍

RMI (Remote Method Invocation) 模型是一种分布式对象应用,使用 RMI 技术可以使一个 JVM 中的对象,调用另一个 JVM 中的对象方法并获取调用结果。这里的另一个 JVM 可以在同一台计算机也可以是远程计算机。因此,RMI 意味着需要一个 Server 端和一个 Client 端。

Server 端通常会创建一个对象,并使之可以被远程访问。

Client 端调用可以被远程访问的对象上的方法,Client 端就可以和 Server 端进行通信并相互传递信息。

说到这里,是不是发现使用 RMI 在构建一个分布式应用时十分方便,它和 RPC 一样可以实现分布式应用之间的互相通信,甚至和现在的微服务思想都十分类似。

RMI 工作原理

正所谓 “知其然知其所以然”,在开始编写 RMI 代码之前,有必要了解一下 RMI 的工作原理,RMI 中 Client 端是和 Server 端是如何通信的呢?

下图的可以帮助我们理解RMI 的工作流程。

RMI Connection

从图中可以看到,Client 端有一个被称 Stub 的东西,有时也会被成为存根,它是 RMI Client  的代理对象,Stub 的主要功能是请求远程方法时构造一个信息块,RMI 协议会把这个信息块发送给 Server 端。

这个信息块由几个部分组成:

既然 Client 端有一个 Stub 可以构造信息快发送给 Server 端,那么 Server 端必定会有一个接收这个信息快的对象,称为 Skeleton 。

它主要的工作是:

解析信息块中的调用对象标识符和方法描述,在 Server 端调用具体的对象方法。

取得调用的返回值或者异常值。

把返回值进行编组,返回给客户端 Stub.

到这里,一次从  Client 端对 Server 端的调用结果就可以获取到了。

RMI 开发

通过上面的介绍,知道了 RMI 的概念以及 RMI 的工作原理,下面介绍 RMI 的开发流程。

这里会通过一个场景进行演示,假设 Client 端需要查询用户信息,而用户信息存在于 Server 端,所以在 Server 端开放了 RMI 协议接口供客户端调用查询。

RMI Server

Server 端主要是构建一个可以被传输的类 User,一个可以被远程访问的类 UserService,同时这个对象要注册到 RMI 开放给客户端使用。

定义服务器接口(需要继承 Remote 类,方法需要抛出 RemoteException)。

  1. package com.wdbyte.rmi.server; 
  2.  
  3. import java.rmi.Remote; 
  4. import java.rmi.RemoteException; 
  5.  
  6.  
  7.  
  8. public interface UserService extends Remote { 
  9.  
  10.      
  11.     User findUser(String userId) throws RemoteException; 

User 对象在步骤 3 中定义。

实现服务器接口(需要继承 UnicastRemoteObject 类,实现定义的接口)。

  1. package com.wdbyte.rmi.server; 
  2.  
  3. import java.rmi.RemoteException; 
  4. import java.rmi.server.UnicastRemoteObject; 
  5.  
  6.  
  7. public class UserServiceImpl extends UnicastRemoteObject implements UserService { 
  8.  
  9.     protected UserServiceImpl() throws RemoteException { 
  10.     } 
  11.  
  12.     @Override 
  13.     public User findUser(String userId) throws RemoteException { 
  14.         // 加载在查询 
  15.          if ("00001".equals(userId)) { 
  16.             User user = new User(); 
  17.             user.setName("金庸"); 
  18.             user.setAge(100); 
  19.             user.setSkill("写作"); 
  20.             return user
  21.         } 
  22.         throw new RemoteException("查无此人"); 
  23.     } 

定义传输的对象,传输的对象需要实现序列化(Serializable)接口。

需要传输的类一定要实现序列化接口,不然传输时会报错。IDEA 中如何生成 serialVersionUID,在文章末尾也附上了简单教程。

  1. package com.wdbyte.rmi.server; 
  2.  
  3. import java.io.Serializable
  4.  
  5.  
  6. public class User implements Serializable { 
  7.  
  8.     private static final long serialVersionUID = 6490921832856589236L; 
  9.  
  10.     private String name
  11.     private Integer age; 
  12.     private String skill; 
  13.  
  14.     public String getName() { 
  15.         return name
  16.     } 
  17.  
  18.     public void setName(String name) { 
  19.         this.name = name
  20.     } 
  21.  
  22.     public Integer getAge() { 
  23.         return age; 
  24.     } 
  25.  
  26.     public void setAge(Integer age) { 
  27.         this.age = age; 
  28.     } 
  29.  
  30.     public String getSkill() { 
  31.         return skill; 
  32.     } 
  33.  
  34.     public void setSkill(String skill) { 
  35.         this.skill = skill; 
  36.     } 
  37.      
  38.     @Override 
  39.     public String toString() { 
  40.         return "User{" + 
  41.             "name='" + name + '\'' + 
  42.             ", age=" + age + 
  43.             ", skill='" + skill + '\'' + 
  44.             '}'
  45.     } 

注册( rmiregistry)远程对象,并启动服务端程序。

服务端绑定了 UserService 对象作为远程访问的对象,启动时端口设置为 1900。

  1. package com.wdbyte.rmi.server; 
  2.  
  3. import java.rmi.Naming; 
  4. import java.rmi.registry.LocateRegistry; 
  5.  
  6.  
  7. public class RmiServer { 
  8.  
  9.     public static void main(String[] args) { 
  10.         try { 
  11.             UserService userService = new UserServiceImpl(); 
  12.             LocateRegistry.createRegistry(1900); 
  13.             Naming.rebind("rmi://localhost:1900/user", userService); 
  14.             System.out.println("start server,port is 1900"); 
  15.         } catch (Exception e) { 
  16.             e.printStackTrace(); 
  17.         } 
  18.     } 

RMI Client

相比 Server 端,Client 端就简单的多。直接引入可远程访问和需要传输的类,通过端口和 Server 端绑定的地址,就可以发起一次调用。

  1. package com.wdbyte.rmi.client; 
  2.  
  3. import java.rmi.Naming; 
  4.  
  5. import com.wdbyte.rmi.server.User
  6. import com.wdbyte.rmi.server.UserService; 
  7.  
  8.  
  9. public class RmiClient { 
  10.     public static void main(String args[]) { 
  11.         User answer; 
  12.         String userId = "00001"
  13.         try { 
  14.             // lookup method to find reference of remote object 
  15.             UserService access = (UserService)Naming.lookup("rmi://localhost:1900/user"); 
  16.             answer = access.findUser(userId); 
  17.             System.out.println("query:" + userId); 
  18.             System.out.println("result:" + answer); 
  19.         } catch (Exception ae) { 
  20.             System.out.println(ae); 
  21.         } 
  22.     } 

RMI  测试

启动 Server 端。

  1. start server,port is 1900 

启动 Client 端。

  1. query:00001 
  2. result:User{name='金庸', age=100, skill='写作'

如果 Client 端传入不存在的 userId。

  1. java.rmi.ServerException: RemoteException occurred in server thread; nested exception is:  
  2.     java.rmi.RemoteException: 查无此人 

serialVersionUID 的生成

IDEA 中生成 serialVersionUID,打开设置,如下图所示勾选。

IDEA 设置

选中要生成 serialVersionUID 的类,按智能提示快捷键。

IDEA serialVersionUID

参考

[1] https://docs.oracle.com/javase/tutorial/rmi/overview.html

 

来源:未读代码内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯