自己写了个Java RMI(远程方法调用)的实现案例

自己简单写了个Java RMI(远程方法调用)的实现案例。

为了更好理解RMI(远程方法调用)、序列化的意义等等,花费三天多的时间肝了一个Java RMI的实现案例。

!!!高能预警!!!

代码量有点大,先附上了简图用于理解

自己写了个Java RMI(远程方法调用)的实现案例

整个过程分为两大步

  • 第一步–注册过程:客户端通过指定路由获取注册中心指定的 远程客户端对象
  • 第二部–服务调用过程:客户端通过 远程客户端对象访问 远程服务端(代理服务)从而访问到真实服务的实现

调整为舒适的姿势,慢慢看…… 废话少说,上代码!!!

1.定义远程标记接口

面向接口编程,具体作用看后面的代码怎么使用

// 标记接口:直接或间接实现MyRMI接口将获得远程调用的能力
public interface MyRMI{
}

2.编写RMI 服务注册中心

注册中心类:用于注册服务和获取服务,核心是hashMap路由表对象

/**
 * 注册中心:维护服务发布的注册表
 */
public class MyRMIRegistry {
    // 默认端口
    public final int REGISTRY_PORT = 10099;
    private String host;
    private int port;
&#xA0;&#xA0;&#xA0;&#xA0;private&#xA0;Map<string, myrmi>&#xA0;bindings;

&#xA0;&#xA0;&#xA0;&#xA0;public&#xA0;MyRMIRegistry(int&#xA0;port){
&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;this.port&#xA0;=&#xA0;port;
&#xA0;&#xA0;&#xA0;&#xA0;}
&#xA0;&#xA0;&#xA0;&#xA0;public&#xA0;MyRMIRegistry(String&#xA0;host,&#xA0;int&#xA0;port){
&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;this.host=host;
&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;this.port=port;
&#xA0;&#xA0;&#xA0;&#xA0;}

&#xA0;&#xA0;&#xA0;&#xA0;public&#xA0;void&#xA0;createRegistry(String&#xA0;serverName,MyRMI&#xA0;myRMI){
&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;//&#xA0;&#x6CE8;&#x518C;&#x670D;&#x52A1;&#xFF0C;&#x5E76;&#x5F00;&#x542F;&#x670D;&#x52A1;
&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;this.bindings&#xA0;=&#xA0;new&#xA0;HashMap<>();
&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;String&#xA0;host&#xA0;=&#xA0;null;
&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;try&#xA0;{
&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;host&#xA0;=&#xA0;Inet4Address.getLocalHost().getHostAddress();
&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;}&#xA0;catch&#xA0;(UnknownHostException&#xA0;e)&#xA0;{
&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;e.printStackTrace();
&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;}
&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;//&#xA0;&#x8DEF;&#x7531;&#x89C4;&#x5219;&#x53EF;&#x81EA;&#x884C;&#x5B9A;&#x4E49;&#xFF0C;&#x53EA;&#x8981;&#x80FD;&#x786E;&#x4FDD;Key&#x552F;&#x4E00;&#x5373;&#x53EF;
&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;String&#xA0;binding&#xA0;=&#xA0;"myrmi://"+host+":"+port+"/"+serverName;
&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;this.bindings.put("myrmi://"+host+":"+port+"/"+serverName,myRMI);
&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;System.out.println("&#x6CE8;&#x518C;&#x7684;&#x670D;&#x52A1;&#x6709;&#xFF1A;"+bindings.keySet().toString());
&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;MyRMIRegistryServer&#xA0;myRMIRegistryServer&#xA0;=&#xA0;new&#xA0;MyRMIRegistryServer(this.port,&#xA0;this.bindings);
&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;Executors.newCachedThreadPool().submit(myRMIRegistryServer);&#xA0;//&#xA0;&#x7EBF;&#x7A0B;&#x6C60;&#x542F;&#x52A8;&#x670D;&#x52A1;

&#xA0;&#xA0;&#xA0;&#xA0;}

&#xA0;&#xA0;&#xA0;&#xA0;public&#xA0;MyRMI&#xA0;getRegistry(String&#xA0;serverName){
&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;Socket&#xA0;socket&#xA0;=&#xA0;null;
&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;ObjectOutputStream&#xA0;out&#xA0;=&#xA0;null;
&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;ObjectInputStream&#xA0;in&#xA0;=&#xA0;null;
&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;MyRMI&#xA0;myRMI&#xA0;=&#xA0;null;
&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;//&#xA0;&#x901A;&#x8FC7;
&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;try&#xA0;{
&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;socket&#xA0;=&#xA0;new&#xA0;Socket(host,&#xA0;port);
&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;out&#xA0;=&#xA0;new&#xA0;ObjectOutputStream(socket.getOutputStream());
&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;out.writeObject("myrmi://"+host+":"+port+"/"+serverName);
&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;in&#xA0;=&#xA0;new&#xA0;ObjectInputStream(socket.getInputStream());
&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;myRMI&#xA0;=&#xA0;(MyRMI)in.readObject();
&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;}&#xA0;catch&#xA0;(IOException&#xA0;e)&#xA0;{
&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;e.printStackTrace();
&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;}catch&#xA0;(ClassNotFoundException&#xA0;e)&#xA0;{
&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;e.printStackTrace();
&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;}
&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;return&#xA0;myRMI;
&#xA0;&#xA0;&#xA0;&#xA0;}
}
</string, myrmi>

RMI 注册中心获取服务的线程:启动注册中心服务,等待客户端来获取路由表中的远程客户端

/**
&#xA0;*&#xA0;RMI&#x6CE8;&#x518C;&#x4E2D;&#x5FC3;&#x83B7;&#x53D6;&#x670D;&#x52A1;&#x7EBF;&#x7A0B;
&#xA0;*/
public&#xA0;class&#xA0;MyRMIRegistryServer&#xA0;implements&#xA0;Runnable&#xA0;{
&#xA0;&#xA0;&#xA0;&#xA0;private&#xA0;int&#xA0;port;
&#xA0;&#xA0;&#xA0;&#xA0;private&#xA0;Map<string, myrmi>&#xA0;bindings;
&#xA0;&#xA0;&#xA0;&#xA0;public&#xA0;MyRMIRegistryServer(Integer&#xA0;port,Map<string, myrmi>&#xA0;bindings){
&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;this.port&#xA0;=&#xA0;port;
&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;this.bindings&#xA0;=&#xA0;bindings;
&#xA0;&#xA0;&#xA0;&#xA0;}

&#xA0;&#xA0;&#xA0;&#xA0;@Override
&#xA0;&#xA0;&#xA0;&#xA0;public&#xA0;void&#xA0;run()&#xA0;{
&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;ServerSocket&#xA0;serverSocket&#xA0;=&#xA0;null;
&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;ObjectOutputStream&#xA0;out&#xA0;=&#xA0;null;
&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;ObjectInputStream&#xA0;in&#xA0;=&#xA0;null;
&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;try&#xA0;{
&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;serverSocket&#xA0;=&#xA0;new&#xA0;ServerSocket(this.port);
&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;while(true){
&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;Socket&#xA0;socket&#xA0;=&#xA0;serverSocket.accept();
&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;in&#xA0;=&#xA0;new&#xA0;ObjectInputStream(socket.getInputStream());
&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;out&#xA0;=&#xA0;new&#xA0;ObjectOutputStream(socket.getOutputStream());
&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;//&#xA0;&#x770B;&#x770B;&#x5BA2;&#x6237;&#x7AEF;&#x60F3;&#x8981;&#x4EC0;&#x4E48;&#x670D;&#x52A1;
&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;String&#xA0;serverName&#xA0;=&#xA0;(String)in.readObject();
&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;Iterator&#xA0;iterator&#xA0;=&#xA0;bindings.keySet().iterator();
&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;while&#xA0;(iterator.hasNext()){
&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;String&#xA0;key&#xA0;=&#xA0;(String)&#xA0;iterator.next();
&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;if(serverName.equals(key)){
&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;//&#xA0;&#x7ED9;&#x5BA2;&#x6237;&#x7AEF;&#x54CD;&#x5E94;&#x670D;&#x52A1;&#x5BF9;&#x8C61;
&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;MyRMI&#xA0;myRMI&#xA0;=&#xA0;bindings.get(key);
&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;out.writeObject(myRMI);
&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;}
&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;}
&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;}
&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;}&#xA0;catch&#xA0;(IOException&#xA0;e)&#xA0;{
&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;e.printStackTrace();
&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;}&#xA0;catch&#xA0;(ClassNotFoundException&#xA0;e)&#xA0;{
&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;e.printStackTrace();
&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;}finally&#xA0;{
&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;//&#xA0;&#x5F02;&#x5E38;&#x540E;&#x8FDB;&#x5165;
&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;try&#xA0;{
&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;if&#xA0;(out!=null)&#xA0;&#xA0;out.close();
&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;if&#xA0;(in!=null)&#xA0;&#xA0;&#xA0;in.close();
&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;if&#xA0;(serverSocket!=null)&#xA0;serverSocket.close();
&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;}&#xA0;catch&#xA0;(IOException&#xA0;e)&#xA0;{
&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;e.printStackTrace();
&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;}
&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;}

&#xA0;&#xA0;&#xA0;&#xA0;}

}
</string, myrmi></string, myrmi>

3.定义要发布的服务接口

需要提供RMI服务的接口,必须继承自定义的MyRMI标记接口

/**
&#xA0;*&#xA0;&#x670D;&#x52A1;&#x63A5;&#x53E3;
&#xA0;*/
public&#xA0;interface&#xA0;Hello&#xA0;extends&#xA0;MyRMI&#xA0;{
&#xA0;&#xA0;&#xA0;&#xA0;public&#xA0;String&#xA0;sayHello(String&#xA0;name);
}

4.服务用到的实体类

/**
&#xA0;*&#xA0;&#x5BF9;&#x8C61;&#x6570;&#x636E;&#x7C7B;&#xFF1A;Person
&#xA0;*/
public&#xA0;class&#xA0;Person&#xA0;implements&#xA0;Serializable&#xA0;{
&#xA0;&#xA0;&#xA0;&#xA0;//&#xA0;&#x5E8F;&#x5217;&#x5316;&#x7248;&#x672C;UID
&#xA0;&#xA0;&#xA0;&#xA0;private&#xA0;static&#xA0;final&#xA0;long&#xA0;serialVersionUID&#xA0;=&#xA0;1L;
&#xA0;&#xA0;&#xA0;&#xA0;private&#xA0;String&#xA0;name;
&#xA0;&#xA0;&#xA0;&#xA0;private&#xA0;int&#xA0;age;
&#xA0;&#xA0;&#xA0;&#xA0;private&#xA0;String&#xA0;sex;

&#xA0;&#xA0;&#xA0;&#xA0;public&#xA0;String&#xA0;getName()&#xA0;{
&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;return&#xA0;name;
&#xA0;&#xA0;&#xA0;&#xA0;}
&#xA0;&#xA0;&#xA0;&#xA0;public&#xA0;void&#xA0;setName(String&#xA0;name)&#xA0;{
&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;this.name&#xA0;=&#xA0;name;
&#xA0;&#xA0;&#xA0;&#xA0;}
&#xA0;&#xA0;&#xA0;&#xA0;public&#xA0;int&#xA0;getAge()&#xA0;{
&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;return&#xA0;age;
&#xA0;&#xA0;&#xA0;&#xA0;}
&#xA0;&#xA0;&#xA0;&#xA0;public&#xA0;void&#xA0;setAge(int&#xA0;age)&#xA0;{
&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;this.age&#xA0;=&#xA0;age;
&#xA0;&#xA0;&#xA0;&#xA0;}
&#xA0;&#xA0;&#xA0;&#xA0;public&#xA0;String&#xA0;getSex()&#xA0;{
&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;return&#xA0;sex;
&#xA0;&#xA0;&#xA0;&#xA0;}
&#xA0;&#xA0;&#xA0;&#xA0;public&#xA0;void&#xA0;setSex(String&#xA0;sex)&#xA0;{
&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;this.sex&#xA0;=&#xA0;sex;
&#xA0;&#xA0;&#xA0;&#xA0;}
&#xA0;&#xA0;&#xA0;&#xA0;@Override
&#xA0;&#xA0;&#xA0;&#xA0;public&#xA0;String&#xA0;toString()&#xA0;{
&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;return&#xA0;"Person{"&#xA0;+&#xA0;"name='"&#xA0;+&#xA0;name&#xA0;+&#xA0;",&#xA0;age="&#xA0;+&#xA0;age&#xA0;+&#xA0;",&#xA0;sex='"&#xA0;+&#xA0;sex&#xA0;+&#xA0;'}';
&#xA0;&#xA0;&#xA0;&#xA0;}
&#xA0;&#xA0;&#xA0;&#xA0;public&#xA0;Person()&#xA0;{
&#xA0;&#xA0;&#xA0;&#xA0;}
&#xA0;&#xA0;&#xA0;&#xA0;public&#xA0;Person(String&#xA0;name,&#xA0;Integer&#xA0;age,&#xA0;String&#xA0;sex)&#xA0;{
&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;this.name&#xA0;=&#xA0;name;
&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;this.age&#xA0;=&#xA0;age;
&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;this.sex&#xA0;=&#xA0;sex;
&#xA0;&#xA0;&#xA0;&#xA0;}
}

5.实现要发布的服务接口

/**
&#xA0;*&#xA0;&#x5BF9;&#x5916;&#x63D0;&#x4F9B;&#x7684;&#x670D;&#x52A1;&#x5B9E;&#x73B0;
&#xA0;*/
public&#xA0;class&#xA0;HelloImpl&#xA0;implements&#xA0;Hello&#xA0;{
&#xA0;&#xA0;&#xA0;&#xA0;private&#xA0;static&#xA0;File&#xA0;file&#xA0;=&#xA0;new&#xA0;File("D:/HelloRMI.txt");
&#xA0;&#xA0;&#xA0;&#xA0;private&#xA0;static&#xA0;List<person>&#xA0;list&#xA0;=&#xA0;new&#xA0;ArrayList<>();

&#xA0;&#xA0;&#xA0;&#xA0;@Override
&#xA0;&#xA0;&#xA0;&#xA0;public&#xA0;String&#xA0;sayHello(String&#xA0;name)&#xA0;{
&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;String&#xA0;result&#xA0;=&#xA0;"&#x6CA1;&#x6709;&#x83B7;&#x53D6;&#x5230;"+name+"&#x7684;&#x4FE1;&#x606F;";
&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;try&#xA0;{
&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;List<person>&#xA0;personList&#xA0;=&#xA0;readList();
&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;for(Person&#xA0;person:personList){
&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;if&#xA0;(person.getName().equals(name)){
&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;result&#xA0;=&#xA0;"Hello&#xA0;,&#xA0;welcome&#xA0;to&#xA0;the&#xA0;RMI!&#xA0;"
&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;+&#xA0;"&#x59D3;&#x540D;&#xFF1A;"+name&#xA0;+&#xA0;"&#xA0;&#x5E74;&#x9F84;&#xFF1A;"+person.getAge()+"&#xA0;&#x6027;&#x522B;&#xFF1A;"+person.getSex();
&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;}
&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;}
&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;}&#xA0;catch&#xA0;(IOException&#xA0;e)&#xA0;{
&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;e.printStackTrace();
&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;}&#xA0;catch&#xA0;(ClassNotFoundException&#xA0;e)&#xA0;{
&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;e.printStackTrace();
&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;}

&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;return&#xA0;result;
&#xA0;&#xA0;&#xA0;&#xA0;}

&#xA0;&#xA0;&#xA0;&#xA0;/**
&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;*&#xA0;&#x751F;&#x6210;&#x6570;&#x636E;&#xFF0C;&#x4E3A;&#x6D4B;&#x8BD5;&#x505A;&#x51C6;&#x5907;
&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;*&#xA0;@param&#xA0;args
&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;*&#xA0;@throws&#xA0;IOException
&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;*&#xA0;@throws&#xA0;ClassNotFoundException
&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;*/
&#xA0;&#xA0;&#xA0;&#xA0;public&#xA0;static&#xA0;void&#xA0;main(String[]&#xA0;args)&#xA0;throws&#xA0;IOException,&#xA0;ClassNotFoundException&#xA0;{
&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;//&#x6570;&#x636E;&#x51C6;&#x5907;&#xFF1A;&#x96C6;&#x5408;&#x7C7B;&#x90FD;&#x5B9E;&#x73B0;&#x4E86;&#x5E8F;&#x5217;&#x5316;&#x63A5;&#x53E3;Serializable
&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;list.add(new&#xA0;Person("&#x5F20;&#x4E09;",&#xA0;38,&#xA0;"&#x7537;"));
&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;list.add(new&#xA0;Person("&#x674E;&#x56DB;",&#xA0;38,&#xA0;"&#x7537;"));
&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;list.add(new&#xA0;Person("&#x5982;&#x82B1;",&#xA0;18,&#xA0;"&#x5973;"));
&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;//&#xA0;&#x6301;&#x4E45;&#x5316;&#x5BF9;&#x8C61;&#x6570;&#x636E;
&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;writerList(list);
&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;//&#xA0;&#x67E5;&#x8BE2;&#x6301;&#x4E45;&#x5316;&#x5BF9;&#x8C61;&#x6570;&#x636E;
&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;List<person>&#xA0;personList&#xA0;=&#xA0;readList();
&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;System.out.println("&#x904D;&#x5386;&#x6301;&#x4E45;&#x5316;&#x5BF9;&#x8C61;&#x6570;&#x636E;>");
&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;for&#xA0;(Person&#xA0;person&#xA0;:&#xA0;personList)&#xA0;{
&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;System.out.println(person);
&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;if&#xA0;(person.getAge()&#xA0;==&#xA0;38)&#xA0;{
&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;person.setAge(18);
&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;}
&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;}

&#xA0;&#xA0;&#xA0;&#xA0;}

&#xA0;&#xA0;&#xA0;&#xA0;public&#xA0;static&#xA0;void&#xA0;writerList(List<person>&#xA0;list)&#xA0;throws&#xA0;IOException&#xA0;{
&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;ObjectOutputStream&#xA0;objectOutputStream&#xA0;=&#xA0;new&#xA0;ObjectOutputStream(new&#xA0;FileOutputStream(file));
&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;objectOutputStream.writeObject(list);
&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;objectOutputStream.close();
&#xA0;&#xA0;&#xA0;&#xA0;}

&#xA0;&#xA0;&#xA0;&#xA0;public&#xA0;static&#xA0;List<person>&#xA0;readList()&#xA0;throws&#xA0;IOException,&#xA0;ClassNotFoundException&#xA0;{
&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;//&#xA0;&#x8BFB;&#x53D6;&#x666E;&#x901A;&#x6587;&#x4EF6;&#x53CD;&#x5E8F;&#x5217;&#x5316;
&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;ObjectInputStream&#xA0;objectInputStream&#xA0;=&#xA0;new&#xA0;ObjectInputStream(new&#xA0;FileInputStream(file));
&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;List<person>&#xA0;personList&#xA0;=&#xA0;(List<person>)&#xA0;objectInputStream.readObject();
&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;objectInputStream.close();
&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;return&#xA0;personList;
&#xA0;&#xA0;&#xA0;&#xA0;}
}
</person></person></person></person></person></person></person>

6.远程客户端的线程类

用于自动生成服务接口(继承了MyRMI标记接口)的远程客户端类:这个类原本是通用类实现,为了方便实现,就直接实现Hello接口了

/**
&#xA0;*&#xA0;&#x8FDC;&#x7A0B;&#x5BA2;&#x6237;&#x7AEF;&#x7684;&#x7EBF;&#x7A0B;&#x7C7B;&#x7684;&#x751F;&#x6210;&#xFF1A;
&#xA0;*&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#x4E3A;&#x4E86;&#x65B9;&#x4FBF;&#x5B9E;&#x73B0;&#xFF0C;&#x8FD9;&#x8FB9;&#x76F4;&#x63A5;&#x5B9E;&#x73B0;&#x670D;&#x52A1;&#x63A5;&#x53E3;&#x7F16;&#x5199;
&#xA0;*/
public&#xA0;class&#xA0;HelloClientThread&#xA0;implements&#xA0;Hello,Serializable&#xA0;{
&#xA0;&#xA0;&#xA0;&#xA0;//&#xA0;&#x5E8F;&#x5217;&#x5316;&#x7248;&#x672C;UID
&#xA0;&#xA0;&#xA0;&#xA0;private&#xA0;static&#xA0;final&#xA0;long&#xA0;serialVersionUID&#xA0;=&#xA0;1L;
&#xA0;&#xA0;&#xA0;&#xA0;private&#xA0;Map<string,object>&#xA0;map&#xA0;=&#xA0;new&#xA0;HashMap<>();&#xA0;//&#xA0;&#x62A5;&#x6587;&#x5BF9;&#x8C61;&#xFF1A;&#x65B9;&#x6CD5;&#x540D;&#x548C;&#x53C2;&#x6570;&#x5BF9;&#x8C61;
&#xA0;&#xA0;&#xA0;&#xA0;private&#xA0;String&#xA0;ip;
&#xA0;&#xA0;&#xA0;&#xA0;private&#xA0;int&#xA0;port;

&#xA0;&#xA0;&#xA0;&#xA0;public&#xA0;HelloClientThread(String&#xA0;ip,&#xA0;int&#xA0;port){
&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;this.ip&#xA0;=&#xA0;ip;
&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;this.port&#xA0;=&#xA0;port;
&#xA0;&#xA0;&#xA0;&#xA0;}

&#xA0;&#xA0;&#xA0;&#xA0;@Override
&#xA0;&#xA0;&#xA0;&#xA0;public&#xA0;String&#xA0;sayHello(String&#xA0;name)&#xA0;{
&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;map.put("sayHello",name);
&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;String&#xA0;result&#xA0;=&#xA0;(String)send();
&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;return&#xA0;result;
&#xA0;&#xA0;&#xA0;&#xA0;}

&#xA0;&#xA0;&#xA0;&#xA0;private&#xA0;Object&#xA0;send(){
&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;Object&#xA0;o&#xA0;=null;
&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;Socket&#xA0;socket&#xA0;=&#xA0;null;
&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;ObjectOutputStream&#xA0;out&#xA0;=&#xA0;null;
&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;ObjectInputStream&#xA0;in&#xA0;=&#xA0;null;
&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;try&#xA0;{
&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;socket&#xA0;=&#xA0;new&#xA0;Socket(ip,&#xA0;port);
&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;out&#xA0;=&#xA0;new&#xA0;ObjectOutputStream(socket.getOutputStream());
&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;in&#xA0;=&#xA0;new&#xA0;ObjectInputStream(socket.getInputStream());
&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;//&#xA0;&#x544A;&#x8BC9;&#x670D;&#x52A1;&#x7AEF;&#x6211;&#x8981;&#x8C03;&#x7528;&#x4EC0;&#x4E48;&#x670D;&#x52A1;
&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;out.writeObject(map);
&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;//&#xA0;&#x83B7;&#x53D6;&#x670D;&#x52A1;&#x5B9E;&#x73B0;&#x5BF9;&#x8C61;
&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;o&#xA0;=&#xA0;in.readObject();
&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;}&#xA0;catch&#xA0;(IOException&#xA0;e)&#xA0;{
&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;e.printStackTrace();
&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;}&#xA0;catch&#xA0;(ClassNotFoundException&#xA0;e)&#xA0;{
&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;e.printStackTrace();
&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;}finally&#xA0;{
&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;try&#xA0;{
&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;if&#xA0;(out!=null)&#xA0;&#xA0;out.close();
&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;if&#xA0;(in!=null)&#xA0;&#xA0;&#xA0;in.close();
&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;if&#xA0;(socket!=null)&#xA0;socket.close();
&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;}&#xA0;catch&#xA0;(IOException&#xA0;e)&#xA0;{
&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;e.printStackTrace();
&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;}
&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;}
&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;return&#xA0;o;
&#xA0;&#xA0;&#xA0;&#xA0;}
}
</string,object>

7.远程服务端的线程类

用于自动生成服务接口(继承了MyRMI标记接口)的远程服务端类:这个类原本也是通用类实现,为了方便实现,部分代码尚未做到解耦通用

/**
&#xA0;*&#xA0;&#x8FDC;&#x7A0B;&#x670D;&#x52A1;&#x7AEF;&#x7684;&#x7EBF;&#x7A0B;&#x7C7B;&#x7684;&#x751F;&#x6210;&#xFF1A;
&#xA0;*&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#x4E3A;&#x4E86;&#x65B9;&#x4FBF;&#x5B9E;&#x73B0;&#xFF0C;&#x8FD9;&#x8FB9;&#x76F4;&#x63A5;&#x5B9E;&#x73B0;&#x670D;&#x52A1;&#x7EBF;&#x7A0B;&#x7C7B;
&#xA0;*/
public&#xA0;class&#xA0;HelloServerThread&#xA0;implements&#xA0;Runnable&#xA0;{
&#xA0;&#xA0;&#xA0;&#xA0;private&#xA0;Integer&#xA0;port;
&#xA0;&#xA0;&#xA0;&#xA0;private&#xA0;MyRMI&#xA0;myRMI;
&#xA0;&#xA0;&#xA0;&#xA0;public&#xA0;HelloServerThread(Integer&#xA0;port,&#xA0;MyRMI&#xA0;myRMI){
&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;this.port&#xA0;=&#xA0;port;
&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;this.myRMI&#xA0;=&#xA0;myRMI;
&#xA0;&#xA0;&#xA0;&#xA0;}

&#xA0;&#xA0;&#xA0;&#xA0;@Override
&#xA0;&#xA0;&#xA0;&#xA0;public&#xA0;void&#xA0;run()&#xA0;{
&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;ServerSocket&#xA0;serverSocket&#xA0;=&#xA0;null;
&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;ObjectOutputStream&#xA0;out&#xA0;=&#xA0;null;
&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;ObjectInputStream&#xA0;in&#xA0;=&#xA0;null;
&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;try&#xA0;{
&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;serverSocket&#xA0;=&#xA0;new&#xA0;ServerSocket(this.port);
&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;while(true){
&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;Socket&#xA0;socket&#xA0;=&#xA0;serverSocket.accept();
&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;in&#xA0;=&#xA0;new&#xA0;ObjectInputStream(socket.getInputStream());
&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;out&#xA0;=&#xA0;new&#xA0;ObjectOutputStream(socket.getOutputStream());
&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;//&#xA0;&#x770B;&#x770B;&#x5BA2;&#x6237;&#x7AEF;&#x60F3;&#x8981;&#x4EC0;&#x4E48;&#x670D;&#x52A1;
&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;Map&#xA0;map&#xA0;=&#xA0;(Map)in.readObject();
&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;Iterator&#xA0;iterator&#xA0;=&#xA0;map.keySet().iterator();
&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;while&#xA0;(iterator.hasNext()){
&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;String&#xA0;key&#xA0;=&#xA0;(String)&#xA0;iterator.next();
&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;if("sayHello".equals(key)){
&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;//&#xA0;&#x7ED9;&#x5BA2;&#x6237;&#x7AEF;&#x54CD;&#x5E94;&#x670D;&#x52A1;&#x5BF9;&#x8C61;
&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;Hello&#xA0;hello&#xA0;=&#xA0;(Hello)myRMI;
&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;String&#xA0;result&#xA0;=&#xA0;hello.sayHello((String)&#xA0;map.get(key));
&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;out.writeObject(result);
&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;}
&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;}
&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;}
&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;}&#xA0;catch&#xA0;(IOException&#xA0;e)&#xA0;{
&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;e.printStackTrace();
&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;}&#xA0;catch&#xA0;(ClassNotFoundException&#xA0;e)&#xA0;{
&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;e.printStackTrace();
&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;}finally&#xA0;{
&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;//&#xA0;&#x5F02;&#x5E38;&#x540E;&#x8FDB;&#x5165;
&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;try&#xA0;{
&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;if&#xA0;(out!=null)&#xA0;&#xA0;out.close();
&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;if&#xA0;(in!=null)&#xA0;&#xA0;&#xA0;in.close();
&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;if&#xA0;(serverSocket!=null)&#xA0;serverSocket.close();
&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;}&#xA0;catch&#xA0;(IOException&#xA0;e)&#xA0;{
&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;e.printStackTrace();
&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;}
&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;}

&#xA0;&#xA0;&#xA0;&#xA0;}
&#xA0;&#xA0;&#xA0;&#xA0;
}

8.远程客户端生成和远程服务端生成和启动的类

/**
&#xA0;*&#xA0;&#x8FDC;&#x7A0B;&#x5BA2;&#x6237;&#x7AEF;&#x751F;&#x6210;&#x548C;&#x8FDC;&#x7A0B;&#x670D;&#x52A1;&#x7AEF;&#x751F;&#x6210;&#x548C;&#x542F;&#x52A8;&#x7684;&#x7C7B;
&#xA0;*/
public&#xA0;class&#xA0;RemoteSocketObject{
&#xA0;&#xA0;&#xA0;&#xA0;//&#xA0;&#x9ED8;&#x8BA4;&#x7AEF;&#x53E3;
&#xA0;&#xA0;&#xA0;&#xA0;private&#xA0;int&#xA0;port=18999;

&#xA0;&#xA0;&#xA0;&#xA0;//&#xA0;&#x6307;&#x5B9A;&#x8FDC;&#x7A0B;&#x901A;&#x8BAF;&#x7AEF;&#x53E3;&#x548C;&#x4EE3;&#x7406;&#x670D;&#x52A1;
&#xA0;&#xA0;&#xA0;&#xA0;public&#xA0;MyRMI&#xA0;createRemoteClient(MyRMI&#xA0;myRMI,int&#xA0;port){
&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;if&#xA0;(port&#xA0;>&#xA0;0)
&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;this.port=port;

&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;MyRMI&#xA0;myRMIClient&#xA0;=&#xA0;null;
&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;try&#xA0;{
&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;//&#xA0;&#x751F;&#x6210;&#x5E95;&#x5C42;&#x901A;&#x8BAF;&#x670D;&#x52A1;&#x7AEF;&#xFF0C;&#x5E76;&#x542F;&#x52A8;
&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;HelloServerThread&#xA0;helloServerThread&#xA0;=&#xA0;new&#xA0;HelloServerThread(this.port,&#xA0;myRMI);
&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;Executors.newCachedThreadPool().submit(helloServerThread);&#xA0;//&#xA0;&#x7EBF;&#x7A0B;&#x6C60;&#x542F;&#x52A8;&#x670D;&#x52A1;
&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;//&#xA0;&#x751F;&#x6210;&#x5E95;&#x5C42;&#x901A;&#x8BAF;&#x5BA2;&#x6237;&#x7AEF;
&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;String&#xA0;localHost&#xA0;=&#xA0;Inet4Address.getLocalHost().getHostAddress();
&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;System.out.println("host="+localHost+",port="+this.port);
&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;myRMIClient=&#xA0;new&#xA0;HelloClientThread(localHost,&#xA0;this.port);
&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;}&#xA0;catch&#xA0;(Exception&#xA0;e)&#xA0;{
&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;e.printStackTrace();
&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;}
&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;return&#xA0;myRMIClient;
&#xA0;&#xA0;&#xA0;&#xA0;}
&#xA0;&#xA0;&#xA0;&#xA0;
}

9.服务发布类

/**
&#xA0;*&#xA0;RMI&#xA0;&#x670D;&#x52A1;&#x53D1;&#x5E03;&#x7C7B;
&#xA0;*/
public&#xA0;class&#xA0;HelloServer&#xA0;{
&#xA0;&#xA0;&#xA0;&#xA0;public&#xA0;static&#xA0;void&#xA0;main(String[]&#xA0;args)&#xA0;{

&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;System.out.println("Create&#xA0;Hello&#xA0;Remote&#xA0;Method&#xA0;Invocation...");
&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;//&#xA0;&#x5B9E;&#x4F8B;&#x5316;&#x4E00;&#x4E2A;Hello
&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;Hello&#xA0;hello&#xA0;=&#xA0;new&#xA0;HelloImpl();
&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;//&#xA0;&#x8F6C;&#x6362;&#x6210;&#x8FDC;&#x7A0B;&#x670D;&#x52A1;&#xFF0C;&#x5E76;&#x63D0;&#x4F9B;&#x8FDC;&#x7A0B;&#x5BA2;&#x6237;&#x7AEF;
&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;Hello&#xA0;remoteClient&#xA0;=&#xA0;(Hello)new&#xA0;RemoteSocketObject().createRemoteClient(hello,&#xA0;0);
&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;//&#xA0;&#x5C06;&#x670D;&#x52A1;&#x5B9E;&#x73B0;&#x6258;&#x7BA1;&#x5230;Socket&#x670D;&#x52A1;
&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;MyRMIRegistry&#xA0;myRMIRegistry&#xA0;=&#xA0;new&#xA0;MyRMIRegistry(16000);
&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;//&#xA0;&#x5F00;&#x542F;&#x7EBF;&#x7A0B;&#x670D;&#x52A1;
&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;myRMIRegistry.createRegistry("Hello",remoteClient);

&#xA0;&#xA0;&#xA0;&#xA0;}
}

10.客户端测试类

/**
&#xA0;*&#xA0;&#x5BA2;&#x6237;&#x7AEF;&#x6D4B;&#x8BD5;&#x7C7B;
&#xA0;*&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#x5BA2;&#x6237;&#x7AEF;&#x53EA;&#x77E5;&#x9053;&#x670D;&#x52A1;&#x63A5;&#x53E3;&#x3001;&#x670D;&#x52A1;&#x53D1;&#x5E03;&#x7684;&#x5730;&#x5740;&#x548C;&#x670D;&#x52A1;&#x53D1;&#x5E03;&#x7684;&#x540D;&#x79F0;
&#xA0;*/
public&#xA0;class&#xA0;TestHello&#xA0;{
&#xA0;&#xA0;&#xA0;&#xA0;public&#xA0;static&#xA0;void&#xA0;main(String[]&#xA0;args)&#xA0;{
&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;//&#xA0;&#x6CE8;&#x610F;&#x4E0D;&#x662F;127.0.0.1&#xFF0C;&#x4E0D;&#x77E5;&#x9053;host&#x7684;&#x770B;server&#x7AEF;&#x542F;&#x52A8;&#x540E;&#x6253;&#x5370;&#x7684;&#x4FE1;&#x606F;
&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;//&#xA0;&#x7AEF;&#x53E3;16000&#x662F;&#x6CE8;&#x518C;&#x4E2D;&#x5FC3;&#x7684;&#x7AEF;&#x53E3;&#xFF0C;&#x5E95;&#x5C42;&#x4EE3;&#x7406;&#x670D;&#x52A1;&#x7684;&#x7AEF;&#x53E3;&#x5BA2;&#x6237;&#x7AEF;&#x65E0;&#x9700;&#x77E5;&#x9053;
&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;MyRMIRegistry&#xA0;client&#xA0;=&#xA0;new&#xA0;MyRMIRegistry("192.168.233.1",&#xA0;16000);
&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;Hello&#xA0;hello&#xA0;=&#xA0;(Hello)&#xA0;client.getRegistry("Hello");
&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;System.out.println(hello.sayHello("&#x5F20;&#x4E09;"));
&#xA0;&#xA0;&#xA0;&#xA0;}
}

11.总结

所有代码整下来,在真正的场景中:

客户端只知道:TestHello类、Hello接口定义、MyRMI标记接口、MyRMIRegistry注册类代码(路由表中只知道Key,不知道具体值);

服务端只知道:Hello接口、HelloImpl服务实现类、MyRMI标记接口、MyRMIRegistry注册类代码(路由表中知道Key和具体值);

关于其他的代码实现都是无感的,为了简单实现远程客户端和远程服务端,将服务接口耦合到两者上了,未做到解耦通用。

自己写了个Java RMI(远程方法调用)的实现案例

Java往期文章

Java全栈学习路线、学习资源和面试题一条龙

我心里优秀架构师是怎样的?

免费下载经典编程书籍

更多优质文章和资源👇

自己写了个Java RMI(远程方法调用)的实现案例

原创不易、三联支持:分享,点赞,在看👇

Original: https://www.cnblogs.com/dennyLee2025/p/15969994.html
Author: 渊渟岳
Title: 自己写了个Java RMI(远程方法调用)的实现案例

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/569055/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球