ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

Java RMI 框架(远程方法调用)

2022-06-14 19:31:26  阅读:172  来源: 互联网

标签:调用 Java 服务器端 对象 接口 存根 RMI 远程 客户端


转载 https://blog.51cto.com/haolloyin/332426 仅供学习使用,侵权必删

 RMI(即Remote Method Invoke 远程方法调用)。在Java中,只要一个类extends了java.rmi.Remote接口,即可成为存在于服务器端的远程对象,供客户端访问并提供一定的服务。JavaDoc描述:Remote 接口用于标识其方法可以从非本地虚拟机上调用的接口。任何远程对象都必须直接或间接实现此接口。只有在“远程接口”(扩展 java.rmi.Remote 的接口)中指定的这些方法才可远程使用。 
注意:extends了Remote接口的类或者其他接口中的方法若是声明抛出了RemoteException异常,则表明该方法可被客户端远程访问调用。 
同时,远程对象必须实现java.rmi.server.UniCastRemoteObject类,这样才能保证客户端访问获得远程对象时,该远程对象将会把自身的一个拷贝以Socket的形式传输给客户端,此时客户端所获得的这个拷贝称为“存根”,而服务器端本身已存在的远程对象则称之为“骨架”。其实此时的存根是客户端的一个代理,用于与服务器端的通信,而骨架也可认为是服务器端的一个代理,用于接收客户端的请求之后调用远程方法来响应客户端的请求。 
RMI 框架的基本原理大概如下图,应用了代理模式来封装了本地存根与真实的远程对象进行通信的细节。

 

 

下面给出一个简单的RMI 应用,其中类图如下:其中IService接口用于声明服务器端必须提供的服务(即service()方法),ServiceImpl类是具体的服务实现类,而Server类是最终负责注册服务器远程对象,以便在服务器端存在骨架代理对象来对客户端的请求提供处理和响应。

 

 

各个类的源代码如下:
IService接口:
 
import java.rmi.Remote;
import java.rmi.RemoteException;
public interface IService extends Remote {
  //声明服务器端必须提供的服务
  String service(String content) throws RemoteException;
}
ServiceImpl实现类:
import java.rmi.RemoteException;
//UnicastRemoteObject用于导出的远程对象和获得与该远程对象通信的存根。
import java.rmi.server.UnicastRemoteObject;

public class ServiceImpl extends UnicastRemoteObject implements IService {

  private String name;

  public ServiceImpl(String name) throws RemoteException {
    this.name = name;
  }
  @Override
  public String service(String content) {
    return "server >> " + content;
  }
}
Server类:
/*
* Context接口表示一个命名上下文,它由一组名称到对象的绑定组成。
* 它包含检查和更新这些绑定的一些方法。
*/
import javax.naming.Context;
/*
* InitialContext类是执行命名操作的初始上下文。    
* 该初始上下文实现 Context 接口并提供解析名称的起始点。
*/
import javax.naming.InitialContext;
public class Server {
  public static void main(String[] args) {
    try {
      //实例化实现了IService接口的远程服务ServiceImpl对象
      IService service02 = new ServiceImpl("service02");
      //初始化命名空间
      Context namingContext = new InitialContext();
      //将名称绑定到对象,即向命名空间注册已经实例化的远程服务对象
      namingContext.rebind("rmi://localhost/service02", service02);
    } catch (Exception e) {
      e.printStackTrace();
    }
    System.out.println("服务器向命名表注册了1个远程服务对象!");
  }
}
Client类:
import javax.naming.Context;
import javax.naming.InitialContext;

public class Client {
  public static void main(String[] args) {
    String url = "rmi://localhost/";
    try {
      Context namingContext = new InitialContext();
      // 检索指定的对象。 即找到服务器端相对应的服务对象存根
      IService service02 = (IService) namingContext.lookup(url
          + "service02");
      Class stubClass = service02.getClass();
      System.out.println(service02 + " 是 " + stubClass.getName()
          + " 的实例!");
      // 获得本底存根已实现的接口类型
      Class[] interfaces = stubClass.getInterfaces();
      for (Class c : interfaces) {
        System.out.println("存根类实现了 " + c.getName() + " 接口!");
      }
      System.out.println(service02.service("你好!"));
    } catch (Exception e) {
      e.printStackTrace();
    }
  }
}
将以上代码保存于某一目录下,先运行“start rmiregistry”来启动JDK自带的注册表程序,它用于保存Server类注册的远程对象并允许远程客户端的请求访问;然后运行服务器端的Server类,即“start java Server”,该程序向注册表中注册具体的远程对象;最后才是运行客户端程序来查找并获得服务器端的远程对象存根,此时才能使用存根对象与服务器进行通信,命令是“java Client”。注意:上面命令中的start的功能是重新打开一个DOS窗口。
运行结果如下:

 

 


 
其实整个简单的RMI 应用中各个类的交互时序如下图:

 

 

以上内容是学习参考了孙卫琴老师的《Java网络编程精解》一书的RMI一章,加上了自己个人的理解总结,希望能与大家互相学习共同进步!

转载 仅供个人学习使用

标签:调用,Java,服务器端,对象,接口,存根,RMI,远程,客户端
来源: https://www.cnblogs.com/YoungSone/p/16376036.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有