【IT168 技术文档】
1.1 实践描述
服务器提供个人信息资料库(HashMap),客户端通过姓名来进行调用查询,预期返回该个人属性集对象(Properties)。主要是介绍RMI的具体应用和远程接口函数值的返回。
1.2 实践过程
1.2.1 远程接口定义
public interface Personal extends Remote { //------------------------------------------------------------------------- //Get personal info. by name public Properties getPersonal(String __name) throws RemoteException;
1.2.2 定义服务端执类
public class PersonalImpl extends UnicastRemoteObject implements Personal { //Personal info. container private HashMap m_infoMap; //------------------------------------------------------------------------- public PersonalImpl() throws RemoteException { m_infoMap = new HashMap(100); //Append personal info. records addPersonal("Paul", "Male", "1980/11/20", "Travelling, Fishing, Programming"); …… } //------------------------------------------------------------------------- //Add personal info. to map container by name private void addPersonal(String __name, String __sex, String __birthday, String __hobby) { Properties props = new Properties(); //Set properties props.setProperty("name", __name); props.setProperty("sex", __sex); props.setProperty("birthday", __birthday); props.setProperty("hobby", __hobby); //Add to map m_infoMap.put(__name, props); } //------------------------------------------------------------------------- //Get personal info. by name public Properties getPersonal(String __name) { return ((Properties)m_infoMap.get(__name) ); }
1.2.3 定义服务端程序入口
public class PersonalServer { //------------------------------------------------------------------------- public static void main(String [] args) throws RemoteException, MalformedURLException { PersonalServer server = new PersonalServer(); } //------------------------------------------------------------------------- public PersonalServer() throws RemoteException, MalformedURLException { PersonalImpl p1 = new PersonalImpl(); //Bind remote object with name Naming.rebind("Personal.Information.Server", p1); }
1.2.4 执行rmic工具生成存根类
1.2.5 启动RMI注册表工具(rmiregistry)
1.2.6 执行服务端入口类
1.2.7 检查远程对象注册
该步骤主要为了检查RMI服务端是否启动正常。以下是检查注册用代码:
public class CheckBinds { //------------------------------------------------------------------------- public static void main(String [] args) throws Exception { CheckBinds checher = new CheckBinds(); } //------------------------------------------------------------------------- public CheckBinds() throws Exception { try { String [] bindsList = Naming.list(""); //List all binds for(int i = 0; i < bindsList.length; ++i) { System.out.println(bindsList[i]); }
检查程序应该输出://:1099/Personal.Information.Server才说明远程对象绑定正常。
1.2.8 将Server目录中存根类和远程接口定义类拷贝到Client目录1.2.9 定义客户端程序入口,检索远程对象并执行其接口
public PersonalClient(String __name) throws RemoteException, MalformedURLException, NotBoundException { String urlPrefix = "rmi://192.168.1.147:1099/"; //Look up the remote object by URL Personal p = (Personal)Naming.lookup(urlPrefix + "Personal.Information.Server"); //Invoke the remote interface Properties props = p.getPersonal(__name); …… //Print the result set showPersonal(props); }
请注意异常处理,至少需要抛出3种异常错误。
1.3 过程说明
实践中,远程接口定义的返回值为Properties,很显然,在不同的Java虚拟机甚至是不同的主机,Properties变量是无法通过内存地址来实现共享的。但是Properties是可序列化对象(见下图2),通过序列化机制可以实现服务器端到客户端的对象拷贝,在客户端构造一个与服务器端相同的Properties对象提供客户端使用。
读者可以思考,如果远程接口定义的返回值的类型不是这么简单,而是例如DataSouce对象,Connection对象或者ResultSet对象时,RMI还能运行得如此正常吗?带着这个问题,我们将踏上迷茫而又有趣的RMI与JDBC的组合应用之旅。