很多人知道rmic工具(为远程对象生成 stub 和 skeleton),但是却很少人了解rmid,笔者在这里介绍一下rmid,并简单谈谈它的使用,rmid像rmic一样,
是一个可执行程序,用于启动系统激活进程,以便能够在 Java 虚拟机上注册和激活对象。 rmid的出现是为了解决分布式处理的性能问题,如果一个系统存在
着大量的分布式对象,而对象无限期存在于内存中并一直保持活动状态,这将占用太多系统资源,另外,客户机需要保存对对象的持久引用的能力,这样在一个
系统崩溃后可以重新建立对象之间的通讯。为了解决这些问题,就有了RMI激活架构,可以让对象在需要时激活,不需要时就钝化。关于RMI激活概念,读者可以
参看http://www.oneedu.cn/xxyd/Print.asp?ArticleID=4277&Page=1。
一般应用会把rmid和rmiregistry结合起来使用,一个专门用于激活和钝化,另外一个专门用于注册和查找,其实,rmid也有注册和查找对象的功能,所以
我们可以单独使用rmid来做rmi测试,我们先举一个例子说明,
先启动rmid,
rmid -J-Djava.security.policy=%LOCATION%/test.policy -port 1099
rmid在1099端口监听,默认是1098,现在用1099,目的很简单,替换rmiregistry。这里的LOCATION是指poliy文件存放的位置,
我们可以写一个全权开放的policy文件,
策略文件test.policy
grant {
permission java.security.AllPermission;
};
我们的server程序如下,
接口Server.java
package com.lxj;
import java.rmi.Remote;
import java.rmi.RemoteException;
public interface Server extends Remote{
String say() throws RemoteException;
}
实现类Server1Impl.java
package com.lxj.test1;
import java.rmi.MarshalledObject;
import java.rmi.Naming;
import java.rmi.RMISecurityManager;
import java.rmi.RemoteException;
import java.rmi.activation.Activatable;
import java.rmi.activation.ActivationDesc;
import java.rmi.activation.ActivationGroup;
import java.rmi.activation.ActivationGroupDesc;
import java.rmi.activation.ActivationGroupID;
import java.rmi.activation.ActivationID;
import java.util.Properties;
import com.lxj.Server;
public class Server1Impl extends Activatable implements Server {
public Server1Impl(ActivationID id, MarshalledObject data) throws RemoteException {
super(id, 0);
}
public String say() throws RemoteException {
System.out.println("begin say invoking");
return "hello,world";
}
public static void main(String[] args) throws Exception{
System.setSecurityManager(new RMISecurityManager());
Properties props = new Properties();
props.put("java.security.policy", "D:/ae_eclipse/workspace/test/bin/test.policy");
ActivationGroupDesc.CommandEnvironment ace = null;
ActivationGroupDesc group = new ActivationGroupDesc(props, ace);
System.out.println("Begin register group");
System.setProperty("java.rmi.activation.port","1099");
ActivationGroupID agi = ActivationGroup.getSystem().registerGroup(group);
System.out.println("End register group");
String location = "file:/D:/ae_eclipse/workspace/test/bin/";
MarshalledObject data = null;
ActivationDesc desc = new ActivationDesc(agi, "com.lxj.test1.Server1Impl", location, data);
Server server = (Server)Activatable.register(desc);
Naming.bind("Server",server);
System.out.println("Exported Server");
}
}
注:读者自己测试时请替换程序中的路径为自己本机的路径。
运行Server1Impl对服务进行注册,注意设置CLASSPATH,
java -Djava.security.policy=%LOCATION%/test.policy -Djava.rmi.server.codebase=file:/%LOCATION_2%/ com.lxj.test1.Server1Impl
LOCATION_2是指class文件的位置,运行完毕,如果没有错误表明已经注册激活组成功。
现在我们可以用客户端类来调用我们的服务,
package com.lxj.test1;
import java.rmi.Naming;
import com.lxj.Server;
public class Client1 {
public static void main(String[] args) throws Exception {
Server server = (Server) Naming.lookup("Server");
//如果是远程服务,可以切换用下面注释掉的代码
//Server server = (Server)java.rmi.registry.LocateRegistry.getRegistry("localhost",1099).lookup("Server");
System.out.println(server.say());
}
}
运行Client1以后,我们会发现在服务器进程列表中多了一个java进程,这个进程是rmid的子进程,每个激活组都会有一个jvm进程。
下面我们可以让rmid和rmiregistry一起工作,不过我们先要小小地调整一下Server1Impl.java代码,把
System.setProperty("java.rmi.activation.port","1099");这句话注释掉然后重新编译,因为现在rmiregistry要使用1099端口,
rmid还是使用它的1098,当然,这些端口号都可以修改。
先启动rmid,
rmid -J-Djava.security.policy=test.policy
然后启动rmiregistry
rmiregistry
再注册激活组和注册虚拟引用
java -Djava.security.policy=%LOCATION%/test.policy -Djava.rmi.server.codebase=file:/%LOCATION_2%/ com.lxj.test1.Server1Impl
运行Client1就会得到前面一样的结果。
最后要说明的是rmid(父进程)的系统参数会自动传给激活组对应的java子进程,比如rmid -J-Dcorp=lxj,我们可以在我们的服务类中通过
System.getProperties().getProperty("corp")取到。