关于rmi的研究
2013-12-07 13:48
204 查看
关于rmi的研究
rmi有两个主要问题:
1. 调用如何从客户端传输到服务器端
这个问题的是通过stub来解决的,stub负责和服务器通信,将调用传输到服务器并接收
返回值
2. 由于stub类可以通过工具生成,但初始化必须在服务器端完成,所有如何将一个可用的
stub传输到客户端就是我们最关心的问题
注:在1.4中stub类是必须的,在5.0中使用UnicastRemoteObject类可以不需要stub类,
而由动态生成的Proxy类(实现远程接口,InvocationHandler是
RemoteObjectInvocationHandler)代替,具体见5.0的文档。如果不使用
UnicastRemoteObject类,则stub类在服务器端是必须的
rmi的核心问题是如何将一个可用的stub传输到客户端,大致有两种方法:
1. 最直观的方法,服务器和客户端直接建立连接,用任何可用的协议传输stub,缺点显而
易见,客户端必须明确的知道服务器的地址及相关信息
2. 使用注册中心,如:rmiregistry和JNDI。这里主要讨论使用rmiregistry的情况
有一点需要注意,这里传输的只是stub的实例,而不是stub类的定义。所有stub类文件必须
在客户端和服务器端的classpath中,否则会抛出ClassNotFoundException。这样要求客户
端确实有些过分,我们希望客户端只要远程接口的定义就够了,这实际上很容易办到,下面
我们就来讨论这个问题
Dynamic code downloading usingRMI
(http://java.sun.com/j2se/1.4.2/docs/guide/rmi/codebase.html)
要下载类必须设置RMISecurityManager,默认是禁止下载的
客户端可以通过网络自动下载stub,此时stub不需要在客户端的classpath中,只需要远程
接口即可。
由rmiregistry作为注册中心的远程调用
在服务器绑定远程对象到rmiregistry时,rmiregistry必须能够找到该对象的stub,它在三
个地方寻找:
1. 启动它时的CLASSPATH环境变量
2. 启动它时所在的文件夹作为classpath寻找
3. 该stub中的codebase,这个值由服务器通过系统属性 java.rmi.server.codebase 设置
若找不到则无法绑定
客户端通过rmiregistry lookup到stub对象,虚拟机从两个位置寻找stub类的定义:
1. classpath中寻找
2. stub中的codebase,这个值由rmi服务器通过系统属性 java.rmi.server.codebase设置
由以上分析可见,服务器端只要正确设置了codebase,无论何种情况,远程调用都能顺利完成
不仅客户端可以从服务器下载类,服务器也可以从客户端下载类,只需要在客户端设置
codebase,安装RMISecurityManager即可
若服务器允许下载类,则客户端有可能在服务器上运行任何他希望的代码,如以下代码:
package rmi.client;
importjava.io.Serializable;
publicclass
Runner implements
Runnable, Serializable {
publicvoid
run() {
System.out.println("i'mrunner");
}
}
服务器端生成stub并放在classpath中,codebase设置为能找到stub的路径,运行rmiregistry,
运行服务器。
客户端只需要Service类在classpath中,设置codebase为能找到Runner的路径,运行客户端。
客户端会从服务器下载stub,服务器会从客户端下载Runner。Runner可以执行任何操作甚至破坏
服务器上的数据。
多次运行客户端可以发现count在增长,也就是说对于export出的远程对象,状态是始终保存的
rmi有两个主要问题:
1. 调用如何从客户端传输到服务器端
这个问题的是通过stub来解决的,stub负责和服务器通信,将调用传输到服务器并接收
返回值
2. 由于stub类可以通过工具生成,但初始化必须在服务器端完成,所有如何将一个可用的
stub传输到客户端就是我们最关心的问题
注:在1.4中stub类是必须的,在5.0中使用UnicastRemoteObject类可以不需要stub类,
而由动态生成的Proxy类(实现远程接口,InvocationHandler是
RemoteObjectInvocationHandler)代替,具体见5.0的文档。如果不使用
UnicastRemoteObject类,则stub类在服务器端是必须的
rmi的核心问题是如何将一个可用的stub传输到客户端,大致有两种方法:
1. 最直观的方法,服务器和客户端直接建立连接,用任何可用的协议传输stub,缺点显而
易见,客户端必须明确的知道服务器的地址及相关信息
2. 使用注册中心,如:rmiregistry和JNDI。这里主要讨论使用rmiregistry的情况
有一点需要注意,这里传输的只是stub的实例,而不是stub类的定义。所有stub类文件必须
在客户端和服务器端的classpath中,否则会抛出ClassNotFoundException。这样要求客户
端确实有些过分,我们希望客户端只要远程接口的定义就够了,这实际上很容易办到,下面
我们就来讨论这个问题
Dynamic code downloading usingRMI
(http://java.sun.com/j2se/1.4.2/docs/guide/rmi/codebase.html)
要下载类必须设置RMISecurityManager,默认是禁止下载的
客户端可以通过网络自动下载stub,此时stub不需要在客户端的classpath中,只需要远程
接口即可。
由rmiregistry作为注册中心的远程调用
在服务器绑定远程对象到rmiregistry时,rmiregistry必须能够找到该对象的stub,它在三
个地方寻找:
1. 启动它时的CLASSPATH环境变量
2. 启动它时所在的文件夹作为classpath寻找
3. 该stub中的codebase,这个值由服务器通过系统属性 java.rmi.server.codebase 设置
若找不到则无法绑定
客户端通过rmiregistry lookup到stub对象,虚拟机从两个位置寻找stub类的定义:
1. classpath中寻找
2. stub中的codebase,这个值由rmi服务器通过系统属性 java.rmi.server.codebase设置
由以上分析可见,服务器端只要正确设置了codebase,无论何种情况,远程调用都能顺利完成
不仅客户端可以从服务器下载类,服务器也可以从客户端下载类,只需要在客户端设置
codebase,安装RMISecurityManager即可
若服务器允许下载类,则客户端有可能在服务器上运行任何他希望的代码,如以下代码:
// 远程接口定义 package rmi.server; import java.rmi.Remote; import java.rmi.RemoteException; public interface Service extends Remote { public void hello() throws RemoteException; public void runThread(Runnable thread) throws RemoteException; }
// 远程接口实现,main方法作为服务器 package rmi.server; import java.rmi.Naming; import java.rmi.RMISecurityManager; import java.rmi.RemoteException; import java.rmi.server.RemoteStub; import java.rmi.server.UnicastRemoteObject; import java.security.Permission; public class ServiceImpl implements Service { private RemoteStub stub; private int count; public ServiceImpl() throws RemoteException { stub = UnicastRemoteObject.exportObject(this); count = 0; } public void hello() throws RemoteException { System.out.println("Hello World: count = " + (++count)); } public void runThread(Runnable thread) throws RemoteException { Thread t = new Thread(thread); t.start(); } public RemoteStub getStub() { return stub; } public static void main(String[] args) { System.setProperty("java.rmi.server.ignoreStubClasses", "true"); System.setProperty("java.rmi.server.codebase", "file:///E:\\\\bahamut\\\\JavaWorkspace\\\\rmiserver\\\\classes\\\\"); if (System.getSecurityManager() == null) { System.setSecurityManager(new RMISecurityManager() { public void checkPermission(Permission p) { } }); } try { ServiceImpl service = new ServiceImpl(); Naming.rebind("service", service); System.out.println("Server ready"); } catch (Exception e) { e.printStackTrace(); } } }
// 客户端 package rmi.client; import java.rmi.Naming; import java.rmi.RMISecurityManager; import java.security.Permission; import rmi.server.Service; public class ServiceClient { public static void main(String[] args) { System.setProperty("java.rmi.server.codebase", "file:///E:\\\\bahamut\\\\JavaWorkspace\\\\rmiclient\\\\classes\\\\"); if (System.getSecurityManager() == null) { System.setSecurityManager(new RMISecurityManager() { public void checkPermission(Permission p) { } }); } try { Service service = (Service) Naming.lookup("service"); service.hello(); Runnable runner = new Runner(); service.runThread(runner); } catch (Exception e) { e.printStackTrace(); } } }
package rmi.client;
importjava.io.Serializable;
publicclass
Runner implements
Runnable, Serializable {
publicvoid
run() {
System.out.println("i'mrunner");
}
}
服务器端生成stub并放在classpath中,codebase设置为能找到stub的路径,运行rmiregistry,
运行服务器。
客户端只需要Service类在classpath中,设置codebase为能找到Runner的路径,运行客户端。
客户端会从服务器下载stub,服务器会从客户端下载Runner。Runner可以执行任何操作甚至破坏
服务器上的数据。
多次运行客户端可以发现count在增长,也就是说对于export出的远程对象,状态是始终保存的
相关文章推荐
- 关于UIView的autoresizingMask属性的研究
- 关于UIView的autoresizingMask属性的研究
- 关于MySQL分表操作的研究
- 关于盘符里某些文件夹删除不了的解决方案研究
- 关于嵌入式图形项目研究
- 关于Python的super用法研究
- 关于右值引用的粗略研究
- 关于oc中遍历的效率算法研究
- 关于我对于tomcat6 研究两天的经验总结
- 关于javascript中Math对象的属性与方法研究
- 关于Xcode编译性能优化的研究工作总结
- 关于javascript动态网页的研究
- 关于Java/RMI/JBoss/EJB/WebService/JMS的使用
- 关于检测输入正误的提示的研究
- 关于UIView的autoresizingMask属性的研究
- SpringMVC关于json、xml自动转换的原理研究
- 关于中文处理方面的研究
- 关于组织申报2014年度省级应用技术研究与开发计划项目的通知
- 关于获取各种浏览器可见窗口大小的一点点研究
- 关于分布式事务、两阶段提交、一阶段提交、Best Efforts 1PC模式和事务补偿机制的研究 转载