• RMI基础篇


         远程方法调用(Remote Method Invocation,RMI)从JDK1.1就已经实现,它大大增强了Java开发分布式应用的能力。

         RMI可以实现通过网络完成不同JVM间的通信,不仅可以传递基本的数据类型,也可以传递对象。

         RMI是JVM间的通信,如果服务器或客户端不是Java语言开发的,可以考虑web service或者corba。

         RMI可以实现调用的透明性及安全性,客户端本身不关心功能是怎么实现的,只需要调用服务器端代码并关心结果即可。功能只限制于服务器端,客户端无法任意进行操作,也提供了安全性。

         RMI实际应用的场景为:处于安全性及性能的考虑,将某些操作的具体实现放在了服务器端。客户端想进行这些操作就需要使用RMI,去调用另一个JVM(经常是不同的PC上)中的方法并得到希望的结果。

         

          RMI利用JNDI在服务器端注册客户端需要调用的类。具体的调用是存根和骨架之间完成的,可以看做是客户端和服务器端的代理。

            

          下面是一个RMI的简单的例子,各个类的作用都有说明。

      IHello定义了服务器和客户端间通信的接口,客户端只要调用IHello中的方法即可。

          IHello需要继承Remote接口,所有方法都要抛出RemoteException,否则编译不过。

    /**
    * 定义一个远程接口,必须继承Remote接口,其中需要远程调用的方法必须抛出RemoteException异常 
    */ 
    public interface IHello extends Remote { 
    
        public User user = new User();
        public User getUser()  throws RemoteException;;
        public void setUser(User user)  throws RemoteException;;
        /** 
         * 简单的返回“Hello World!"字样 
        */ 
        public String helloWorld() throws RemoteException; 
    
        /** 
         * 一个简单的业务方法,根据传入的人名返回相应的问候语 
         */ 
        public String sayHelloToSomeBody() throws RemoteException; 
    }

      HelloImpl是服务器端实际实现的方法,客户端通过RMI实际调用的就是HelloImpl中的实现。

    /**
    * 远程的接口的实现 
    */ 
    public class HelloImpl extends UnicastRemoteObject implements IHello { 
    
         private User user;
         public User getUser() {
    	return user;
         }
    
         public void setUser(User user) {
    	this.user = user;
         }
    
         private static final long serialVersionUID = -8403069777370518716L;
    
         /** 
         * 因为UnicastRemoteObject的构造方法抛出了RemoteException异常,因此这里默认的构造方法必须写,必须声明抛出RemoteException异常 
         * @throws RemoteException 
         */ 
        public HelloImpl() throws RemoteException { 
        } 
    
        /** 
         * 简单的返回“Hello World!"字样 
         */ 
        public String helloWorld() throws RemoteException { 
            return "Hello World!"; 
        } 
    
        /** 
         * 一个简单的业务方法,根据传入的人名返回相应的问候语 
         */ 
        public String sayHelloToSomeBody() throws RemoteException { 
            return user.getName() + "!"; 
        } 
    }

      HelloServer完成的是注册功能,将上面实际工作的HelloImpl进行注册,客户端调用时查找已经注册的HelloImpl实例并调用即可。

          注册的地址是localhost的8888端口。实际中应用时将localhost改为具体的IP即可。

    /**
    * 创建RMI注册表,启动RMI服务,并将远程对象注册到RMI注册表中。 
    */ 
    public class HelloServer { 
        private static User user = new User();
    	
        public User getUser() {
    	return user;
        }
    
        public void setUser(User user) {
    	this.user = user;
        }
    
        public static void main(String args[]) { 
            try { 
                //创建一个远程对象 
            	HelloImpl rhello = new HelloImpl(); 
                //本地主机上的远程对象注册表Registry的实例,并指定端口为8888,这一步必不可少(Java默认端口是1099),必不可缺的一步,缺少注册表创建,则无法绑定对象到远程注册表上 
                LocateRegistry.createRegistry(8888); 
    
                //把远程对象注册到RMI注册服务器上,并命名为RHello 
                //绑定的URL标准格式为:rmi://host:port/name(其中协议名可以省略,下面两种写法都是正确的) 
                Naming.bind("rmi://localhost:8888/RHello",rhello); 
    //          Naming.bind("//localhost:8888/RHello",rhello); 
    
                System.out.println(">>>>>INFO:远程IHello对象绑定成功!"); 
            } catch (RemoteException e) { 
                System.out.println("创建远程对象发生异常!"); 
                e.printStackTrace(); 
            } catch (AlreadyBoundException e) { 
                System.out.println("发生重复绑定对象异常!"); 
                e.printStackTrace(); 
            } catch (MalformedURLException e) { 
                System.out.println("发生URL畸形异常!"); 
                e.printStackTrace(); 
            } 
        } 
    }  

      HelloClient模拟了客户端的调用,从localhost的8888端口找到注册的HelloImpl实例并调用。

    /**
    * 客户端测试,在客户端调用远程对象上的远程方法,并返回结果。 
    */ 
    public class HelloClient { 
        public static void main(String args[]){ 
            try { 
                //在RMI服务注册表中查找名称为RHello的对象,并调用其上的方法 
                IHello rhello =(IHello) Naming.lookup("rmi://localhost:8888/RHello"); 
                System.out.println(rhello.helloWorld()); 
                User user = new User();
                user.setName("inso");
                rhello.setUser(user);
                System.out.println(rhello.sayHelloToSomeBody()); 
            } catch (NotBoundException e) { 
                e.printStackTrace(); 
            } catch (MalformedURLException e) { 
                e.printStackTrace(); 
            } catch (RemoteException e) { 
                e.printStackTrace();   
            } 
        } 
    }

      User用于客户端调用服务器端代码时传递的参数,说明RMI支持传递对象需要实现Serializable接口

    import java.io.Serializable;
    
    public class User implements Serializable{
    
    	private static final long serialVersionUID = -4631891643752276172L;
    	
    	private String name;
    
    	public String getName() {
    		return "user's name is " + name;
    	}
    
    	public void setName(String name) {
    		this.name = name;
    	}
    
    }

      先启动HelloServer注册实例,再启动HelloClient进行调用即可看到结果。

          还可以将IHello.java,HelloClient.java,User.java拷贝到另外的机器上,模拟客户端实现真正的分布式测试。将服务器端和客户端的localhost改为具体的IP即可。

  • 相关阅读:
    mybatis
    Spring原理
    JS 之继承
    HTTP协议简介2
    JS 之原型,实例,构造函数之间的关系
    HTTP协议简介1
    freemarker语法简介
    CSS 动画之十-图片+图片信息展示
    JS实现颜色值的转换
    抓包工具charles的使用
  • 原文地址:https://www.cnblogs.com/lnlvinso/p/3903049.html
Copyright © 2020-2023  润新知