rmi 工作原理
下图是RMI的体系结构:
通过RMI的体系结构,已经可以看出RMI的大致工作原理:
服务器端提供服务,服务中要暴露可以调用的远程方法,以接口的形式表现,这样在客户端可以通过服务接口来调用远程方法,实现复杂的业务逻辑。在服
务器端,首先要对接口中提供的方法实现,以便客户端调用能够完成一定的业务逻辑;接着需要生成Skeleton,在Skeleton中真正地实现了对商业
方法的调用,完成了客户请求的调用的过程,将获取到的调用方法的结果通过序列化机制返回给客户端,进行应答。在客户端,通过Stub来接收服务器返回的数
据(对象),即在这里进行了反序列化,也就是读取网络传输的字节流,进而进行重构。在Skeleton和Stub中,都对网络通信进行了处理,例如建立套
接字,建立网络连接,为实际的业务需要做好准备。
可见,客户端并没有真正地执行与服务器端组件进行直接交互。
这里,有个重要的概念,就是Java对象序列化机制。序列化,就是将对象写入流,以便能够在网络上传输对象,它是输出端执行的。反序列化,也就是
在接收端,为了能够获取传输的对象,需要将对象传输而来的字节流进行重构,重新得到完整的该对象。Java对象序列化的过程,是对已有的类的实例进行序列
化,首先要存在一个具体的实例。
下面通过在客户端调用服务器端的方法,实现一个例子,可以很直观地模拟RMI工作,从而进一步深化对RMI工作机制的理解。我使用Oracle JDeveloper 10g开发测试。
开发过程
1、在服务接口中,将客户端可以进行调用的方法暴露给客户端。
ShirdrnService接口中列出了可以调用的方法,ShirdrnService接口如下所示:
- package org.shirdrn.rmi.server;
- import java.io.IOException;
- public interface ShirdrnService {
- public String getServerTime() throws IOException, ClassNotFoundException;
- public String getGreetings () throws IOException, ClassNotFoundException;
- }
2、在服务器端要真正实现服务接口中的这些方法,ShirdrnServiceImpl类实现了ShirdrnService接口中列出的方法。
ShirdrnServiceImpl类的实现如下所示:
- package org.shirdrn.rmi.server;
- import java.io.IOException;
- import java.util.Date;
- public class ShirdrnServiceImpl implements ShirdrnService {
- public ShirdrnServiceImpl() {
- }
- public String getServerTime() throws IOException, ClassNotFoundException{
- Date date = new Date();
- String time = date.toLocaleString();
- return time;
- }
- public String getGreetings() throws IOException, ClassNotFoundException{
- Date date = new Date();
- int hour = date.getHours();
- String greetings = "";
- if(hour < 12 && hour > 6){
- greetings = "上午好!";
- }
- else if(hour <= 18 && hour > 12){
- greetings = "下午好!";
- }
- else{
- greetings = "晚上好!";
- }
- return greetings;
- }
- }
3、客户端Stub的实现
ShirdrnStub类实现了ShirdrnService接口,它是客户端获取服务结果数据最直接的实现。然而,它并没有与服务器端真正实现服务接口的实现类直接打交道,而是通过网络传输获取到调用方法的执行结果数据。
- package org.shirdrn.rmi.client;
- import java.io.IOException;
- import java.io.ObjectInputStream;
- import java.io.ObjectOutputStream;
- import java.net.Socket;
- import java.net.UnknownHostException;
- import org.shirdrn.rmi.server.ShirdrnService;
- public class ShirdrnStub implements ShirdrnService{
- Socket socket;
- public ShirdrnStub() {
- try {
- socket = new Socket("56987b31c0b246d",8888);
- } catch (UnknownHostException e) {
- e.printStackTrace();
- System.out.println("[信息]创建套接字异常:未知的主机名称。");
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
- public String getServerTime() throws IOException, ClassNotFoundException {
- ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream());
- oos.writeObject("getServerTime");
- oos.flush();
- ObjectInputStream ois = new ObjectInputStream(socket.getInputStream());
- return (String)ois.readObject();
- }
- public String getGreetings() throws IOException, ClassNotFoundException {
- ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream());
- oos.writeObject("getGreetings");
- oos.flush();
- ObjectInputStream ois = new ObjectInputStream(socket.getInputStream());
- return (String)ois.readObject();
- }
- }
4、服务器端Skeleton的实现
ShirdrnSkeleton类继承了Thread,因此它可以启动服务器端线程,而且是单线程。在
ShirdrnSkeleton中,真正与提供服务实现的类进行了交互。在建立起连接以后,首先获取到客户端调用的方法,根据客户的选择来直接与服务的实
现交互,执行方法获得执行结果数据,从而将结果数据进行序列化,通过网络传输给客户完成应答过程。
实例化ShirdrnSkeleton类的一个实例后,启动线程,这很像是一个服务器端监听器,监听客户端动作,从而完成服务的请求。
- package org.shirdrn.rmi.server;
- import java.io.ObjectInputStream;
- import java.io.ObjectOutputStream;
- import java.net.ServerSocket;
- import java.net.Socket;
- public class ShirdrnSkeleton extends Thread {
- ShirdrnServiceImpl shirdrnServiceImpl;
- public ShirdrnSkeleton(ShirdrnServiceImpl shirdrnServiceImpl) {
- this.shirdrnServiceImpl = shirdrnServiceImpl;
- }
- public void run() {
- try {
- ServerSocket serverSocket = new ServerSocket(8888);
- Socket socket = serverSocket.accept();
- while(socket != null){
- ObjectInputStream ois = new ObjectInputStream(socket.getInputStream());
- String method = (String)ois.readObject();
- if(method.equals("getServerTime")){
- String serverTime = shirdrnServiceImpl.getServerTime();
- ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream());
- oos.writeObject(serverTime);
- oos.flush();
- }
- if(method.equals("getGreetings")){
- String greetings = shirdrnServiceImpl.getGreetings();
- ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream());
- oos.writeObject(greetings);
- oos.flush();
- }
- }
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
- public static void main(String[] args){
- ShirdrnServiceImpl ssi = new ShirdrnServiceImpl();
- ShirdrnSkeleton skeleton = new ShirdrnSkeleton(ssi);
- skeleton.start();
- }
- }
5、客户端测试程序
通过ShirdrnClient类中的主函数,实现了对服务器端提供的服务接口中的方法进行调用:
- package org.shirdrn.rmi.client;
- import java.io.IOException;
- import org.shirdrn.rmi.server.ShirdrnService;
- public class ShirdrnClient {
- public ShirdrnClient() {
- }
- public static void main(String[] args) throws IOException,
- ClassNotFoundException {
- ShirdrnService stub = new ShirdrnStub();
- System.out.println("正在获取服务器时间...");
- System.out.println("服务器时间 : "+stub.getServerTime());
- System.out.println("正在获取问候语...");
- System.out.println("问候语为 : "+stub.getGreetings());
- }
- }
6、测试过程
心得总结
1、客户端是直接通过实例化一个Stub,因为Stub实现了服务方暴露的接口,所以可以直接通过一个Stub的实例来调用服务方法。但是,这并没有直接调用服务方的服务接口的实现。
2、服务方具有服务接口的真正实现。而真正调用服务接口实现类是在服务器端的Skeleton中,在Skeleton中负责调用真正的服务实现,将执行结果返回给客户端,屏蔽了方法调用的实现细节。
3、客户端Stub和服务器端Skeleton之间建立起网络连接,进行了网络通信,主要就是对执行结果进行传输/接收,Skeleton将结果通过网络传输到客户端,而Stub通过代理接口接收传输而来的结果数据。
rmi 工作原理的更多相关文章
- Webservice工作原理及实例
Web Service工作原理及实例 一.Web Service基本概念 Web Service也叫XML Web Service WebService是一种可以接收从Internet或者In ...
- 分布式的几件小事(二)dubbo的工作原理
1.dubbo的工作原理 ①整体设计 图例说明: 图中左边淡蓝背景的为服务消费方使用的接口,右边淡绿色背景的为服务提供方使用的接口,位于中轴线上的为双方都用到的接口. 图中从下至上分为十层,各层均为单 ...
- 菜鸟学Struts2——Struts工作原理
在完成Struts2的HelloWorld后,对Struts2的工作原理进行学习.Struts2框架可以按照模块来划分为Servlet Filters,Struts核心模块,拦截器和用户实现部分,其中 ...
- 【夯实Nginx基础】Nginx工作原理和优化、漏洞
本文地址 原文地址 本文提纲: 1. Nginx的模块与工作原理 2. Nginx的进程模型 3 . NginxFastCGI运行原理 3.1 什么是 FastCGI ...
- HashMap的工作原理
HashMap的工作原理 HashMap的工作原理是近年来常见的Java面试题.几乎每个Java程序员都知道HashMap,都知道哪里要用HashMap,知道HashTable和HashMap之间 ...
- 【Oracle 集群】ORACLE DATABASE 11G RAC 知识图文详细教程之RAC 工作原理和相关组件(三)
RAC 工作原理和相关组件(三) 概述:写下本文档的初衷和动力,来源于上篇的<oracle基本操作手册>.oracle基本操作手册是作者研一假期对oracle基础知识学习的汇总.然后形成体 ...
- ThreadLocal 工作原理、部分源码分析
1.大概去哪里看 ThreadLocal 其根本实现方法,是在Thread里面,有一个ThreadLocal.ThreadLocalMap属性 ThreadLocal.ThreadLocalMap t ...
- Servlet的生命周期及工作原理
Servlet生命周期分为三个阶段: 1,初始化阶段 调用init()方法 2,响应客户请求阶段 调用service()方法 3,终止阶段 调用destroy()方法 Servlet初始化阶段: 在 ...
- 代码管理工具 --- git的学习笔记二《git的工作原理》
通过几个问题来学习代码管理工具之git 一.git是什么?为什么要用它?使用它的好处?它与svn的区别,在Mac上,比较好用的git图形界面客户端有 git 是分布式的代码管理工具,使用它是因为,它便 ...
随机推荐
- AppScan用来进行漏洞扫描
https://www.cnblogs.com/mawenqiangios/p/8573525.html
- Python数据分析-----数据分类
1.常见的分类算法主要有: (1)KNN算法 (2)贝叶斯方法 (3)决策树 (4)人工神经网络 (5)支持向量机(SVM) 2.KNN算法 (1)KNN应用场景: 比方说样本中有很多零食.很多电器. ...
- 网络教程(10)回顾ARP和ping数据包
Ping 192.168.20.2 ICMP Echo (Internet Control Message Protocol ICMP Echo request ICMP Echo reply 收到I ...
- 【JavaScript框架封装】数据类型检测模块功能封装
数据类型检测封装后的最终模块代码如下: /*数据类型检验*/ xframe.extend(xframe, { // 鸭子类型(duck typing)如果它走起路来像鸭子,叫起来也是鸭子,那么它就是鸭 ...
- Python3爬虫环境配置
一.包管理工具Anaconda安装 1.安装直接在官网下载最新版本的 https://www.continuum.io/downloads 2.配置环境变量PATH:C:\Users\Administ ...
- Ubuntu 15.10配置OpenCV
本系列文章由 @yhl_leo 出品,转载请注明出处. 文章链接: http://blog.csdn.net/yhl_leo/article/details/50635705 1 安装前准备 安装以下 ...
- xml01 验证
xml 验证 拥有正确的格式的xml是"形势良好"的xml 通过DTD验证的xml是"合法的"xml
- HelloWorld编译正常运行报noclassdeffounderror
修改环境变量classpath: 原理: classpath是搜索java类库的路径:当你输入命令“java HelloWorld“时,会根据classpath寻找HelloWorld.class:一 ...
- 导入项目后下载jar包问题理解
1.导入,然后你下载的jar包,jar下载成功,并不代表你项目里的代码就能用这个jar包了. 你必须还要本地添加进classpath.必须手动添加进类路径 2.总结就是:下载jar包是下载jar包,添 ...
- chmod和chown命令具体使用方法
Linux下数字表示文件的操作权限(777,755,..) Linux下.查看某路径下用(ls -l)查看全部文件的具体属性列表时.会看到文件的操作权限.类似"drwxr-xr-x" ...