2008-11-15
rmi 找不到stub问题
转自http://sun-cat.iteye.com/blog/80278
转自http://bbs.cjsdn.net/post/view?bid=2&id=35316&sty=3
今天,又看了一回JBUILDER关于RMI的帮助,终于解决了些重要的疑问。看过这阵子贴子的人应该都知道这段时间关于RMI有很多问题出现,我也看了那些贴子,有的问题没有解决,有的“解决”了,但根本就没有用正确的方法。以下是我的经验(但是这不是RMI入门教程,没有基础的请暂时收藏,以后学RMI时相信可以给你些帮助)。这些东西过来人肯定知道,但是为什么他们从来都不告诉我们呢?是不愿,还是不屑呢?
首先要说的是最常见的一个问题,客户端找不到XXX_stub.class文件。这个问题问的人最多(包括我自己以前也来问过)。在CSDN上,甚至于我看到的两本(我就看过两本)译过来的中文书上提出的解决办法,或潜在的解决方法就是在java的参数-classpath中加入XXX_stub.class文件相应路径。确实,问题一下子解决了,但是我心里感觉十分不妥!有没有人想过,对于一个客户端,难道每个客户端都要在本地有一个XXX_stub.class文件吗?那么试想一个Applet,自己就是临时从server上下载来的,难道它有那个可能在用户本地机上“刚好”找到它要调用的RMI Server 的XXX_stub.class文件吗?所以,XXX_stub.class文件的获得也应该是动态的下载!应该用codebase参数,但是我用codebase参数还是不行(找不到XXX_stub.class文件),试了一个星期都没有解决。(最后再说这个问题的解决)
第二是RMI Server运行时找不到XXX_stub.class文件。有些同志可能是一时大意没有用rmic来编译。但是很多人已经用rmic编译生成了XXX_stub.class文件与骨架文件。但是运行RMI Server时还是找不到XXX_stub.class文件,为什么?其实这个时候,找不到XXX_stub.class文件的不是你的Server,而是rmiregistry程序。你的classpath里当然是有相应录的,但是rmiregistry起动时的路径里可没有。但是,你先别着急把rmiregistry的参数里加上相应路径,因为JBuilder里说千万让rmiregistry知道你的stub文件的路径,因为这样客户端动态下载stub时会出问题(我还没有证实过这一点的正确性)。解决办法是在你起动RMI server时加codebase参数,如下:
java -Djava.rmi.server.codebase=http://YourServerName/YourPackagePathName/ packageName.serverClassName
而你的Web Server的YourServerName/YourPackagePathName/目录下应该有一个与你的包同名的目录,那个目录下有相应stub文件。这个问题就圆满解决了。
第三,不起作用的客户端java.rmi.server.codebase。接着一个问题说,我去掉了客户端classpath目录里的含有stub文件的那一个目录。加上了如下参数:
-Djava.rmi.server.codebase=http://YourServerName/YourPackagePathName/
但是出现错误:
java.lang.ClassNotFoundException: hellormi.GetMessageImpl_Stub (no security manager: RMI class loader disabled)
classNotFoundException的意思是找不到相应类,但是我确认了自已的参数没有错,而且Web Server也没有任何问题。今天在看JBuilder自带帮助时,忽然发现在客户端例子里它竟然也写了:System.setSecurityManager(new RMISecurityManager())。这在我的两本书里都没有看到,而且其中一本书上还明确地说,客户端里不需要任何安全设置。我想了想才大梦初醒:你lookup的时候他当然不用生成安全管理器,但是当你要从server动态下载类的时候它就要用了!加上这一句之后还没有完全OK。要象Server起动时那样给一个java.security.policy属性允许它做相应socket工作(否则会出安全性异常),之后客户端就能自动从主机下载了stub文件了。
最后补充一点,可以通过编码System.setProperty("java.rmi.server.codebase","http://YourServerName/YourPackagePathName/")来代替手工输入属性,但是一定要注意把它放在System.setSecurityManager(new RMISecurityManager())之前。
rmi 找不到stub问题
转自http://sun-cat.iteye.com/blog/80278
转自http://bbs.cjsdn.net/post/view?bid=2&id=35316&sty=3
今天,又看了一回JBUILDER关于RMI的帮助,终于解决了些重要的疑问。看过这阵子贴子的人应该都知道这段时间关于RMI有很多问题出现,我也看了那些贴子,有的问题没有解决,有的“解决”了,但根本就没有用正确的方法。以下是我的经验(但是这不是RMI入门教程,没有基础的请暂时收藏,以后学RMI时相信可以给你些帮助)。这些东西过来人肯定知道,但是为什么他们从来都不告诉我们呢?是不愿,还是不屑呢?
首先要说的是最常见的一个问题,客户端找不到XXX_stub.class文件。这个问题问的人最多(包括我自己以前也来问过)。在CSDN上,甚至于我看到的两本(我就看过两本)译过来的中文书上提出的解决办法,或潜在的解决方法就是在java的参数-classpath中加入XXX_stub.class文件相应路径。确实,问题一下子解决了,但是我心里感觉十分不妥!有没有人想过,对于一个客户端,难道每个客户端都要在本地有一个XXX_stub.class文件吗?那么试想一个Applet,自己就是临时从server上下载来的,难道它有那个可能在用户本地机上“刚好”找到它要调用的RMI Server 的XXX_stub.class文件吗?所以,XXX_stub.class文件的获得也应该是动态的下载!应该用codebase参数,但是我用codebase参数还是不行(找不到XXX_stub.class文件),试了一个星期都没有解决。(最后再说这个问题的解决)
第二是RMI Server运行时找不到XXX_stub.class文件。有些同志可能是一时大意没有用rmic来编译。但是很多人已经用rmic编译生成了XXX_stub.class文件与骨架文件。但是运行RMI Server时还是找不到XXX_stub.class文件,为什么?其实这个时候,找不到XXX_stub.class文件的不是你的Server,而是rmiregistry程序。你的classpath里当然是有相应录的,但是rmiregistry起动时的路径里可没有。但是,你先别着急把rmiregistry的参数里加上相应路径,因为JBuilder里说千万让rmiregistry知道你的stub文件的路径,因为这样客户端动态下载stub时会出问题(我还没有证实过这一点的正确性)。解决办法是在你起动RMI server时加codebase参数,如下:
java -Djava.rmi.server.codebase=http://YourServerName/YourPackagePathName/ packageName.serverClassName
而你的Web Server的YourServerName/YourPackagePathName/目录下应该有一个与你的包同名的目录,那个目录下有相应stub文件。这个问题就圆满解决了。
第三,不起作用的客户端java.rmi.server.codebase。接着一个问题说,我去掉了客户端classpath目录里的含有stub文件的那一个目录。加上了如下参数:
-Djava.rmi.server.codebase=http://YourServerName/YourPackagePathName/
但是出现错误:
java.lang.ClassNotFoundException: hellormi.GetMessageImpl_Stub (no security manager: RMI class loader disabled)
classNotFoundException的意思是找不到相应类,但是我确认了自已的参数没有错,而且Web Server也没有任何问题。今天在看JBuilder自带帮助时,忽然发现在客户端例子里它竟然也写了:System.setSecurityManager(new RMISecurityManager())。这在我的两本书里都没有看到,而且其中一本书上还明确地说,客户端里不需要任何安全设置。我想了想才大梦初醒:你lookup的时候他当然不用生成安全管理器,但是当你要从server动态下载类的时候它就要用了!加上这一句之后还没有完全OK。要象Server起动时那样给一个java.security.policy属性允许它做相应socket工作(否则会出安全性异常),之后客户端就能自动从主机下载了stub文件了。
最后补充一点,可以通过编码System.setProperty("java.rmi.server.codebase","http://YourServerName/YourPackagePathName/")来代替手工输入属性,但是一定要注意把它放在System.setSecurityManager(new RMISecurityManager())之前。