1.RMI基本原理
RMI框架为远程对象分别生成了客户端代理和服务端代理。(HelloWorld的实例中可以看到客户端端的远程对象为代理类。)位于客户端的代理类称为存根STUB,服务端的代理类称为骨架SKELETON。存根与骨架通过SOCKET进行通信。服务端与客户端之间传送的方法参数或返回值,必须是远程对象(Remote接口也集成Serializable接口)、可序列化对象、基本类型。
2.分布式垃圾回收
RMI框架采用分布式垃圾收集机制(DGC)来管理远程对象的生命周期,DGC的主要规则是,只有当一个远程对象不受到任何本地引用和远程引用,这个对象才会结束生命周期,并且可以被本地Java虚拟机的垃圾回收器回收。
服务器端如何知道客户端持有一个远程对象的远程引用呢?当客户端获得了一个服务器端的远程对象的存根时,就会向服务器发送一条租约通知,告诉服务器自己持有这个远程对象的引用了。客户端对这个远程对象有一个租约期限。租约期限可通过系统属性java.rmi.dgc.leaseValue来设置。默认为10分钟。当到达了租约期限的一半时间,客户端如果还持有远程引用,就会像服务器发送租约通知。如果在租约到期后,服务器端没有继续受到客户端的新的租约通知,服务器端就会认为这个客户已经不在持有远程对象的引用了。
RMI框架管理远程对象的生命周期的过程对应用程序是透明的。远程对象希望在不受到任何引用时执行一些操作,如释放占用的相关资源,以便安全地结束生命周期,这样的远程对象需要实现java.rmi.server.Unreferenced接口。
3.一个复杂点的应用
该程序模拟股票服务端往APP端推送股票实时价格。
package com.wilian.rmi.stock.server; import java.rmi.Remote; import java.rmi.RemoteException; import com.wilian.rmi.stock.client.StockQuote; /** * 服务端注册类,用户管理客户端的连接与释放 * @author wilian * */ public interface StockQuoteRegistry extends Remote { void registerClient(StockQuote client) throws RemoteException; void unregisterClient(StockQuote client) throws RemoteException; }
package com.wilian.rmi.stock.server; import java.rmi.RemoteException; import java.rmi.server.UnicastRemoteObject; import java.rmi.server.Unreferenced; import java.util.HashSet; import java.util.Iterator; import java.util.Random; import com.wilian.rmi.stock.client.StockQuote; /** * 服务端实现类型 * @author wilian * */ public class StockQuoteRegistryImpl extends UnicastRemoteObject implements Runnable,Unreferenced, StockQuoteRegistry { protected HashSet<StockQuote> clients; protected StockQuoteRegistryImpl() throws RemoteException { this.clients=new HashSet<StockQuote>(); } @Override public void registerClient(StockQuote client) throws RemoteException { clients.add(client); System.out.println("加入一个客户端"); } @Override public void unregisterClient(StockQuote client) throws RemoteException { clients.remove(client); System.out.println("删除一个无效客户端"); } /** * 模拟进行股票价格的刷新 */ @Override public void run() { String[] symbols=new String[]{"SUNW","DAL","MSFT","DAL","WUTK","SAMY","KATY"}; Random rand=new Random(); double[] values=new double[symbols.length]; for(int i=0;i<values.length;i++){ values[i]=25.0+rand.nextInt(100); } for(;;){ int sym=rand.nextInt(symbols.length); int change=100-rand.nextInt(201); values[sym]=values[sym]+((double)change)/100.0; if(values[sym]<0) values[sym]=0.01; Iterator<StockQuote> iter = clients.iterator(); while(iter.hasNext()){ StockQuote client = iter.next(); try { client.quote(symbols[sym], values[sym]); } catch (RemoteException e) { System.out.println("删除一个无效的客户端"); iter.remove(); } } try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } } @Override public void unreferenced() { } }
package com.wilian.rmi.stock.client; import java.rmi.RemoteException; import java.rmi.server.UnicastRemoteObject; /** * 股票打印远程实现对象 * @author wilian * */ public class StockQuoteImpl extends UnicastRemoteObject implements StockQuote { protected StockQuoteImpl() throws RemoteException {} @Override public void quote(String stockSymbol, double price) throws RemoteException { System.out.println(stockSymbol+":"+price); } }
package com.wilian.rmi.stock.client; import java.rmi.Remote; import java.rmi.RemoteException; /** * 股票打印接口 * @author Wilian * */ public interface StockQuote extends Remote { void quote(String stockSymbol,double price) throws RemoteException; }
package com.wilian.rmi.stock.server; import java.rmi.RemoteException; import javax.naming.Context; import javax.naming.InitialContext; import javax.naming.NamingException; /** * 服务器端实现 * @author wilian * */ public class Server { public static void main(String[] args) { try { StockQuoteRegistryImpl registry = new StockQuoteRegistryImpl(); Context namingContext=new InitialContext(); namingContext.rebind("rmi:StockQuoteRegistry", registry); //开启后台刷新线程 new Thread(registry).start(); } catch (RemoteException e) { e.printStackTrace(); } catch (NamingException e) { e.printStackTrace(); } } }
package com.wilian.rmi.stock.client; import java.rmi.RemoteException; import javax.naming.Context; import javax.naming.InitialContext; import javax.naming.NamingException; import com.wilian.rmi.server.Flight; import com.wilian.rmi.server.FlightFactory; import com.wilian.rmi.stock.server.StockQuoteRegistry; /** * 客户端 * @author wilian * */ public class Client { public static void main(String[] args) { String url="rmi://localhost/"; try { Context namingContext = new InitialContext(); StockQuoteRegistry registry = (StockQuoteRegistry)namingContext.lookup(url+"StockQuoteRegistry"); StockQuote client =new StockQuoteImpl(); registry.registerClient(client); } catch (NamingException e) { e.printStackTrace(); } catch (RemoteException e) { e.printStackTrace(); } } }
运行截图:
从上面的例子可以看出,服务端也可以通过远程对象回调客户端。
参考资料:《Java网络编程精解》
相关推荐
本示例将深入探讨JDK原生的RMI实现及其应用场景。** 首先,了解RMI的基本概念: 1. **远程接口(Remote Interface)**:这是定义远程方法的接口,必须继承`java.rmi.Remote`。每个远程方法都可能抛出`java.rmi....
"采用JDK实现的日志框架"是一个基于Java Development Kit(JDK)1.4中的`java.util.logging`包构建的日志系统,它旨在提供与流行的Log4j框架类似的灵活性和功能。 `java.util.logging`是Java平台的标准日志API,自...
这得益于JDK5中引入的动态代理技术,该技术允许动态生成Stub和Skeleton类,大大简化了RMI服务的部署过程。 #### JDK5中的RMI新特性 1. **动态代理支持:** 在JDK5之前,开发者需要手动编写大量的代码来生成Stub和...
随着技术的发展,JDK版本也在不断更新,从JDK 1.7升级到JDK 1.8时,可能会遇到与旧版本兼容性问题,特别是对于依赖于特定JDK版本的库。本教程将详细介绍如何在JDK 1.8环境下搭建SSH框架,并列出所需的jar包。 首先...
这些更新能确保RuoYi框架与最新的技术栈保持一致,提高开发效率并提供更好的服务。 在实际测试中,"初步测试可以运行通过"表明升级后的RuoYi框架在JDK 21和Spring Boot 3.2.5环境下能够正常启动和运行,但全面的...
在Java世界中,远程方法调用(Remote Method Invocation,RMI)是一种强大的技术,它允许在不同的Java虚拟机(JVM)之间透明地调用对象的方法。本篇将深入探讨如何利用JDK 1.5版本搭建一个基本的分布式Java RMI程序...
JDK11安装包,JDK11安装包JDK11安装包,JDK11安装包JDK11安装包,JDK11安装包JDK11安装包,JDK11安装包JDK11安装包,JDK11安装包JDK11安装包,JDK11安装包JDK11安装包,JDK11安装包JDK11安装包,JDK11安装包JDK11...
Java RMI(远程方法调用)是Java编程语言中的一项核心技术,自JDK 1.1版本起就被引入,用于构建分布式系统。RMI允许Java对象在不同的Java虚拟机(JVMs)之间进行交互,仿佛这些对象是在同一台机器上一样。这种技术的...
《RMI反序列化及相关工具反制浅析》 RMI(Remote Method Invocation,远程方法调用)是Java中一种用于实现分布式计算的技术,它允许一个Java对象调用另一个在网络另一端的Java对象的方法。然而,RMI的反序列化过程...
与其他分布式对象技术相比,如CORBA和DCOM,RMI是Java平台的标准组成部分,从JDK 1.1开始就内置于Java虚拟机中。这意味着所有的Java系统可以直接相互通信,而无需额外的协议转换。CORBA,由Object Management Group ...
Java Remote Method Invocation (RMI) 是Java平台提供的一种分布式计算技术,它允许在不同网络位置的Java对象之间进行远程调用。RMI是Java在分布式环境中实现对象间通信的重要手段,使得开发者可以像操作本地对象...
标题 "springboot+mybatis+jdk1.7" 指的是一个基于Spring Boot、MyBatis框架,并使用Java Development Kit 1.7版本构建的Web应用项目。这个项目已经搭建完成,具备基本的结构,方便开发者快速启动一个新的Java Web...
JDK 1.4是Java历史上的一个重要版本,发布于2002年2月26日,标志着Java技术向前迈进了一大步。尽管现在已经被更新的版本如JDK 8、JDK 11和JDK 17所取代,但JDK 1.4对于理解Java的发展历程具有重要意义。 **主要特性...
Spring 框架中 JDK 动态代理和 CGLIB 动态代理是 Spring AOP 中一个非常重要的知识点。Spring AOP 框架会根据实际情况选择使用 JDK 的动态代理还是 CGLIB 的动态代理。 JDK 动态代理是 Java 自带的动态代理机制,它...
Jdk升级到1.8版本后,如果项目采用的是SSH框架,原来1.7版本及以下的jar包会启动时报错,整理了Jdk1.8版本所需的SSH框架jar包,这个是老版本的框架 但是运行在jdk1.8版本下的 项目实战 大家可以看看
我一脸懵逼,不要配置环境,jar又放不进去,eclipse又不是神仙,那怎么跑的了rmi,最后经过激烈讨论,得到结果jdk版本过低,两天配不了的情况原因也是rmi是很久以前的技术,对应的文件名字和网站以及eclispe都有大量...
1. **升级Spring版本**:最直接的方式是将Spring框架升级到支持JDK 1.8的版本,例如Spring 4.x或更高版本。这样可以确保所有新特性和优化都得到了支持。 2. **配置源兼容性**:在IDE中,可以设置项目源代码兼容性为...
smart shop电商业务中台 是一款经过百万真实用户检验的电商解决方案,采用稳定核心框架主流互联网技术架构,基于JDK17、spring cloud、Mybatis、Nacos、Redisson、Redis、Canal的微服务框架。中台系统通过订单中心、...
在我们的示例中,我们使用JDK 1.5或更高版本,使用RMI连接方式来连接MBeanServer和Client。我们在机器23上实现了Router类,并在机器26上实现了Client,用于远程访问Router类提供的管理功能。 Router类是一个简单的...
例如,Spring框架的AOP(面向切面编程)和IoC(控制反转)概念在JDK 1.4的环境下得以实现,而Hibernate的ORM(对象关系映射)技术也是基于JDK 1.4提供的JDBC和反射机制。 此外,压缩包中的`j2sdk-1_4_2_13-windows-...