zoukankan      html  css  js  c++  java
  • java基础十一[远程部署的RMI](阅读Head First Java记录)

    方法的调用都是发生在相同堆上的两个对象之间(同一台机器的Java虚拟机),如果想要调用另一台机器上的对象,可以通过Socket进行输入/输出。
    远程过程调用需要创建出4种东西:服务器、客户端、服务器辅助设施、客户端辅助设施
     
    RMI
    Java的JMI提供客户端和服务器端的辅助设施对象(stub和skeleton,现在实际只用stub文件,客户端和服务端用一个)
    辅助设施是实际执行通信的对象,他会让客户端感觉在调用本机,实际上辅助设施类似于代理,将客户端传送的信息通过Socket连接发送给服务端辅助设施,然后服务端辅助设施解包调用真正的服务端的服务,服务辅助设施取得结果后将他通过Socket连接返回给客户端辅助设施,客户端辅助设施解开这些信息传给客户端
     
    远程的服务调用是通过java.rmi.registry来实现的。它提供了RMI注册表的一个类和两个接口,注册表绑定字符串名称和远程对象,可以通过注册表调用远程服务的某个对象
     
    服务器端的service实现了远程调用的真正方法
     
    Client辅助设施和Service辅助设施是同一个文件,在服务器端生成的
     
    创建远程服务
     
    大致步骤如下图所示:
     
    步骤1:创建Remote接口
    定义客户端会调用的方法,stub和服务都会实现此接口。远程接口定义了客户端可以远程调用的方法。
     
    import java.rmi.*;
    public interface MyRemote extends Remote{
         public String sayHello() throws RemoteException;
    }
     
    说明:
    1.接口必须继承Remote
    2.远程调用是有风险的,需要通过抛出一个RemoteException异常强迫客户端注意到这件事
    3.远程方法的参数和返回值必须是primitive或Serializable的
     
    步骤2:实现Remote接口
    这个是真正执行的类,实现接口上的方法,也是客户端会调用的对象,去执行真正的工作
    public class MyRemoteImp1 extends UnicastRemoteObject implements MyRemote{
         public MyRemoteImp1() throws RemoteException{}//UnicastRemoteObject会抛出RemoteException异常,构造函数抛出同样异常
         public String sayHello(){//实现Remote接口的所有方法
              return "Server says,‘Hey’"
         }
    }
     
    说明:
    1.实现Remote的接口
    2.要有与远程有关的功能,可以继承UnicastRemoteObject(UnicastRemoteObject 会抛出RemoteException异常,如果调用需要构造函数也抛出同样的异常)
    3.向RMI registry注册服务
    只有向RMI registry注册了,才能让远程用户存取(一定要RMI registry一定要注册起来否则运行程序会失败),注册对象时RMI 会把stub加到registry中,这是客户端需要的,使用java.rmi.Naming的rebind()注册服务
    try{
         MyRemote service=new MyRemoteIm1();
         Naming.rebind("Remote Hello",service);//将实现的接口类实例向RMI registry注册,帮服务命名(Remote Hello)
    }catch(Exception ex){...}
     
     
    步骤3:用rmic产生stub
    对真正实现的类执行rmic,产生helper类(stub)
    会按照命名规则在远程实现的名称后加上_Stub。
    rmic MyRemoteImp1
    会生成MyRemoteImp1_Stub.class文件
     
     
    步骤4:启动RMI registry(rmiregistry)
    用户会从此处获得代理(客户端的sub/helper对象)
    需要在实现的服务类下去执行命令:rmiregistry
    如果想指定端口号,可以通过【rmiregistry 端口号】来启动
     
    步骤5:启动远程服务
    【java 真正实现的类】启动服务,实现服务的类的实例会向RMI registry注册(注册后才能对用户提供服务)
    java MyRemoteImp1
     
    指定服务端口号
    两种方法:一是程序中指定,二是启动rmiregistry时指定
    程序中指定:
     
    启动rmiregistry指定:【rmiregistry 端口号】
     
    客户端实现
     
    客户端获得stub对象
    直接将服务器上生成的stub文件拷贝到客户端上即可
     
    客户端调用远程方法
    通过Naming.lookup()的静态方法寻找某台IP上注册的远程方法(通过Naming.rebind()注册),返回一个stub对象
    MyRemote service=(MyRemote) Naming.lookup("rmi://127.0.0.1:服务端口号/Remote Hello");
     
    如果Naming.lookup没有指定服务的端口号,则用java默认的1099端口号
     
    说明:
    1.客户端调用服务必须与服务端使用相同的接口类型
    2.Naming.lookup()寻址的格式【rmi://服务器地址/注册的远程方法名】,返回一个stub对象
    3.客户端本地一定要有服务端rmic产生的stub类,否则RMI registry返回的stub对象不会被解序列化
     
     
    RMI的注意事项
    1.在启动远程服务前(java 实现服务的类),必须先启动rmiregistry
    2.参数和返回类型必须是可序列化的
    3.将stub类交给客户端
    4.客户端和服务端一定要能够ping通,否则不能调用
     
    遇到的问题
    问题:
    客户端启动时提示地址非法:java.net.MalformedURLException: invalid URL String: rmi://127.0.0.1:2000/Remote Hello
     
    解决方法:
    将远程的服务地址转换一下编码格式
    String url="rmi://127.0.0.1:2000/Remote Hello";
    url= URLEncoder.encode(url, "UTF-8");
    MyRemote service=(MyRemote) Naming.lookup(url);
     
     
     
  • 相关阅读:
    Android中的Handler, Looper, MessageQueue和Thread
    ANR程序无响应原因及应对办法
    避免内存泄露的一些简单方法
    android内存泄露及OOM介绍
    listview异步加载图片优化
    利用convertView及viewHolder优化Adapter
    Sqlite介绍及其语句
    关于单页面和传统页面跳转的思考
    快速入门Vue
    JS编码
  • 原文地址:https://www.cnblogs.com/meitian/p/5860536.html
Copyright © 2011-2022 走看看