RMI 即远程方法调用
jvm1的类要使用jvm2的一个类的方法可以使用RMI实现
大致思路:jvm2把自己的一个类通过注册表的形式发布出来(通过字符串和类的映射关系)
下面是接口中用到的实体类参数
正式启动服务端的服务即提供URL和类的映射并允许客户端通过代理对象调用其中的方法
jvm1的类要使用jvm2的一个类的方法可以使用RMI实现
大致思路:jvm2把自己的一个类通过注册表的形式发布出来(通过字符串和类的映射关系)
jvm通过这个字符串(类似于远程引用)去获取服务端的类的代理对象,然后调用其中的方法
如上图新建了两个工程一个模拟客户端一个模拟服务端,其中红色部分为公共部分即客户端和服务端一模一样
服务端代码列举:
定义一个接口其中的方法供客户端使用
XML Code
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
package common;
import java.rmi.Remote; import java.rmi.RemoteException; /** * 一个可供远程客户端使用的接口申明 * 其中Remote是一个空接口只是申明这个接口类型的接口中的方法可以被远程的客户端调用 * 由于是远程调用即数据要在网络上传输所有有可能发生网络中断,所以要在方法上显式的抛出 * RemoteException * / public interface MyInterface extends Remote{ String forGood(String name) throws RemoteException; User getUser(String name) throws RemoteException; } |
XML Code
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 |
package common;
import java.io.Serializable; /** * 一个参数实体类 * 当一个实体类要作为参数或者返回结果在网络上传输时必须实现 Serializable接口 * 因为网络上传输的是二进制所以必须实现Serializable并生成serialVersionUID * / public class User implements Serializable { private static final long serialVersionUID = -269370248102064836L; private String name; private int age; public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public User(String name, int age) { super(); this.name = name; this.age = age; } public User() { super(); } @Override public String toString() { return "User [name=" + name + ", age=" + age + "]"; } } |
为接口提供一个实现类
XML Code
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
package server;
import java.rmi.RemoteException; import java.util.HashMap; import java.util.Map; import common.MyInterface; import common.User; /** * 这是远程接口的实现类 * 必须直接或者间接继承 java.rmi.server.UnicastRemoteObject * 因为这个类包含很多支持RMI的方法 * / public class MyImpl extends java.rmi.server.UnicastRemoteObject implements MyInterface{ private static Map <String,User> users = new HashMap <String,User>(); static{ users.put( "A",new User( "A",11)); users.put( "B",new User( "B",12)); users.put( "C",new User( "C",13)); users.put( "D",new User( "D",14)); } public MyImpl() throws RemoteException{ super(); System.out.println( "MyImpl被实例化"); } @Override public String forGood(String name) throws RemoteException { return "hello [ "+name+ " ]"; } @Override public User getUser(String name) throws RemoteException { return users.get(name); } } |
XML Code
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
package server;
import java.net.MalformedURLException; import java.rmi.Naming; import java.rmi.RemoteException; import java.rmi.registry.LocateRegistry; public class RmiServer { public static void main(String[] args){ try { String host = args[0]; System.out.println( "host:"+host); /** * 注册表使用1099端口向外提供一个服务即告诉远程客户端通过1099这个端口找客户端 * 参数传递过来的字符串和服务端的类的对应关系 * 这个过程类似于域名服务器做映射,客户端调用远程方法时会通过一个字符串找到 * 远程服务器上的类执行完方法之后再把结果通过网络传输给客户端 * 客户端就是通过这个端口实现这个功能的 * 上面的host就是运行注册表的服务器一般指服务端ip地址 * / LocateRegistry.createRegistry(1099); String url = "rmi://"+host.trim()+ ":1099/com.lyzx.rmi.server.MyImpl"; MyImpl impl = new MyImpl(); /** * 通过这个方法正式建立url和服务端类(com.lyzx.rmi.server.MyImpl)的映射关系 * 客户端可以通过和url一样的字符串获取com.lyzx.rmi.server.MyImpl的代理对象 * / Naming.rebind(url,impl); System.out.print( "server["+host+ "] is ready...."); } catch (RemoteException e) { e.printStackTrace(); } catch (MalformedURLException e) { e.printStackTrace(); } } } |
客户端模拟使用服务端的服务
XML Code
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
package client;
import java.rmi.Naming; import common.MyInterface; import common.User; public class RmiClient { public static void main(String[] args) { try{ //远程服务器的ip地址 String host = args[0]; String url = "rmi://"+host.trim()+ ":1099/com.lyzx.rmi.server.MyImpl"; /** * 通过这个url获取远程服务器上com.lyzx.rmi.server.MyImpl这个类的代理对象 * / MyInterface f = (MyInterface)Naming.lookup(url); String name = args[1]; String forGood = f.forGood(name); System.out.println(forGood); User user = f.getUser(name); System.out.println(user); }catch(Exception e){ e.printStackTrace(); } } } |
由于服务端的common和客户端的common一样,所以只提供一份代码
有时间的朋友还可以分别把两个项目打包放在linux上进行测试(记得是可运行的包)
使用下面的命令:
java -jar server.jar 192......10
java -jar client.jar 192......10 C