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 jdk原生rmi应用示例
JDK5中,RMI技术已经得到了重大更新。现在使用JDK提供的RMI类,可以相当简单的发布RMI服务! 在JDK5发布之前,使用RMI是一件非常繁琐的事情。甚至很多程序员把EJB当作对RMI的封装,当作RMI的简化版! 而今,RMI已经...
日志框架. 实现了动态的切换和log4j类似功能. 采用jdk1.4 log为底层实现. 下载后可以自己定制相关功能. 可以进一步完善.有兴趣可以加QQ:934547801一起讨论
Jdk升级到1.8版本后,如果项目采用的是SSH框架,原来1.7版本及以下的jar包会启动时报错,整理了Jdk1.8版本所需的SSH框架jar包
适合自学及教授java时查询具体的方法,内含JDK1.6、struts2.0、Hibernate中文API、Spring2.5中文开发参考手册等API
整合 ssm,spring,springmvc,mybatis框架整合,jdk1.8,
JDK11安装包,JDK11安装包JDK11安装包,JDK11安装包JDK11安装包,JDK11安装包JDK11安装包,JDK11安装包JDK11安装包,JDK11安装包JDK11安装包,JDK11安装包JDK11安装包,JDK11安装包JDK11安装包,JDK11安装包JDK11...
java开发框架 jdk 比较好用,亲测无误,请大家下载,放心使用
jdk7 jdk8 jdk9 jdk10 jdk11 jdk12 jdk13 jdk14 (win-64位) 资源共享
我一脸懵逼,不要配置环境,jar又放不进去,eclipse又不是神仙,那怎么跑的了rmi,最后经过激烈讨论,得到结果jdk版本过低,两天配不了的情况原因也是rmi是很久以前的技术,对应的文件名字和网站以及eclispe都有大量...
1. JDK8u232 以下版本的 JDK Registry 端反序列化问题 3. 分析 RMI 相关具 ysoserial exp 、 rmitaste 和
这是java RMI 详解,通过例子加原理的解说,分步骤,通过简单的代码行行解释,看完想不会都难
JDK11、JDK11、JDK11、JDK11、JDK11、JDK11、JDK11、JDK11、JDK11、JDK11、JDK11、JDK11、JDK11、JDK11、JDK11、JDK11、JDK11、JDK11、JDK11、JDK11、JDK11、JDK11、JDK11、JDK11、JDK11、JDK11、JDK11、JDK11、JDK...
新增和增强的 API:JDK 17.0.7 包含了许多新的和增强的 Java API,例如 Java 媒体框架、Java 加密框架、Java 容器平台等,为开发人员提供了更多的工具和功能。 更好的安全性:JDK 17.0.7 包括许多安全改进,例如增强...
jdk 的集合框架的主体结构: Set 成员不能重复 HashSet 外部无序地遍历成员。 成员可为任意Object子类的对象,但如果覆盖了equals方法,同时注意修改hashCode方法。
框架 eclipse + jdk1.8 or jdk14 + swing + sql server 管理员用户密码 admin 123456 模块介绍 管理员 登陆模块 器材管理模块 消防员管理模块 密码重置模块 关于系统模块 退出模块 数据库设计 使用的数据库是...
jdk免安装版jdk免安装版jdk免安装版jdk免安装版
它是整个java开发的核心,想要熟练掌握它,用户还需要一款对应的帮助文档,这款jdk api 1.7就是一个不错的选择,它可以帮助使用java,jdk的用户们通过api及时查找到对应的类,接口,框架等详细信息。
JDK API 1.8.CHM是一款jdk1.8中文版的API帮助文档,可以帮助使用java,jdk的用户们通过api及时查找到对应的类,接口,框架等详细信息的帮助手册。
NULL 博文链接:https://javasam.iteye.com/blog/1848846