当前位置: 首页 > news >正文

JDK RMI探索与使用--序列化

引用类型的传递方式,对于在同一JVM中的传递时,因为参数的引用和程序同属于一个内存,传递起来没有问题,但是不同JVM,一个jvmA对象引用使用另外一个jvmB中的class文件进行实例化,不大可能,RMI是将对象在jvmB中实例化,并将对象发布到注册中心,当jvmA客户端调用的远程对象复制到本地时,通过注册中心找到远程对象在jvmB中的引用,并通过建立socket的方式进行对象数据的复制传输。对象数据的传输,需要将对象序列化为字节,然后使用该字节的副本在C/S之间传递。

在java中,一个对象如果能够被序列化,需要满足下面两个条件

①java基本数据类型;

②实现java.io.Serializable接口

如果存在嵌套对象,嵌套的对象也要是可以序列化的,除非被标识成不用序列化

通过查看代码,可知RMI是使用对象流IO类ObjectOutputStream和ObjectInputStream来实现对象的序列化传输,该流可以将一个对象写出,或者读取一个对象到程序中,也就是执行了序列化和反序列化操作,而需要被序列化和反序列化的类必须实现Serializable 接口。

可以通过一个例子先了解下,这个例子是是将一组Person对象通过ObjectOutputStream的方式存入本地磁盘文件中,然后通过ObjectInputStream的方式将文件中的对象读取到程序里。

首先创建一个Person类,如下:

import java.io.Serializable;

public class Person implements Serializable {
private String name;
    private int age;
    public Person(String name, int age) {
this.name = name;
        this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Student [name="+ name + ", age="+ age + "]";
}
}

Person类需要实现Serializable接口,否则会出现java.io.NotSerializableException异常。

接下来我们通过对象流IO类ObjectOutputStream和ObjectInputStream来实现对对象实例数据的操作。

import java.io.*;
import java.util.ArrayList;
import java.util.List;

public class ObjectIOTest {
public static void main(String[] args) {
writeObject();
getObject();
}
private static void writeObject() {
try {
            List<Person> persons = new ArrayList<>();
persons.add(new Person("zhangsan", 24));
persons.add(new Person("lisi", 25));
persons.add(new Person("wanger", 26));
persons.add(new Person("gouzi", 27));
persons.add(new Person("huizi", 28));
ObjectOutputStream stream =new ObjectOutputStream(
new FileOutputStream(
"D:\\opensource\\javabase\\javarmi\\src\\main\\java\\com\\para\\ser\\person.txt"));
stream.writeObject(persons);
} catch (IOException e) {
            e.printStackTrace();
}
    }
private static void getObject() {
try {
            ObjectInputStream stream = new ObjectInputStream(new FileInputStream("D:\\opensource\\javabase\\javarmi\\src\\main\\java\\com\\para\\ser\\person.txt"));
List<Person> personList = (List) stream.readObject();
            if (personList != null && personList.size() >0) {
for(int i = 0; i < personList.size(); i ++) {
                    System.out.println(personList.get(i));
}
            }
        } catch (IOException e) {
            e.printStackTrace();
} catch (ClassNotFoundException e) {
            e.printStackTrace();
}
    }
}

输出结果如下:

Person [name=zhangsan, age=24]
Person [name=lisi, age=25]
Person [name=wanger, age=26]
Person [name=gouzi, age=27]
Person [name=huizi, age=28]

上面的例子是通过本地磁盘文件作为通信的方式,RMI是通过Socket的方式,Skeleton对象做的事情是将服务实现传入构造参数,获取Stub客户端通过socket传过来的方法调用字符串标识,将请求转发到具体的服务上面,获取结果之后返回给客户端。我们可以简单实现一下。

首先是Stub类

import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.Socket;

public class ObjectStub {

private Socket socket;

    public ObjectStub() throws Throwable {
socket = new Socket("localhost", 8888);
}

public Object getObject()  throws Throwable {
        ObjectOutputStream outStream = new ObjectOutputStream(socket.getOutputStream());
outStream.writeObject("getPerson");
outStream.flush();
ObjectInputStream inStream = new ObjectInputStream(socket.getInputStream());
        return inStream.readObject();
}

public static void main(String[] args) {
try {
            ObjectStub stub = new ObjectStub();
Object o = stub.getObject();
            if(o instanceof Person) {
                System.out.println("获取对象成功:"+ o);
} else  {
                System.out.println("获取对象失败:"+ o);
}
        } catch (Throwable throwable) {
            throwable.printStackTrace();
}
    }
}

然后是Skeleton类

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.ServerSocket;
import java.net.Socket;

public class ObjectSkeleton implements Runnable {

@Override
public void run() {
try {
            ServerSocket serverSocket = new ServerSocket(8888);
Socket socket = serverSocket.accept();

            while (socket != null) {
                ObjectInputStream ois = new ObjectInputStream(socket.getInputStream());
ObjectOutputStream oos =  new ObjectOutputStream(socket.getOutputStream());
String action = (String)ois.readObject();
                if(action.equals("getPerson")) {
                    Person person = new Person("zhangsan", 24);
oos.writeObject(person);
oos.flush();
} else {
                    oos.writeObject("error");
oos.flush();
}
            }
        } catch (IOException | ClassNotFoundException e) {
            e.printStackTrace();
System.exit(0);
}
    }
public static void main(String[] args) {
new Thread(new ObjectSkeleton()).start();
}
}

上面简单实现了如何通过客户端如何通过指定参数获取服务端的对象的例子。这里面只是获取Person一个类,如果是很多个对象,不能每个都写一个参数获取,RMI的方式是要求每个需要远程调用的类都继承Remote类,从服务端获取的都是Remote的子类,是典型的面向对象的编程方式。

更多技术文章

相关文章:

  • Self-supervised Low Light Image Enhancement and Denoising 论文阅读笔记
  • hive窗口函数(开窗函数)
  • SpringMVC:整合SSM
  • 【每日一题】路径总和 III
  • 【Vue】基础系列(三三)指令语法-事件及其修饰符,动态样式,v-model的用法,数据持久化存在本地localStorage
  • 01_JSON的理解
  • 3D感知技术(3)双目立体视觉测距
  • spring学习第二天_Spring Ioc(1)
  • 22-08-30 西安JUC(03) Callable接口、阻塞队列4套方法、ThreadPool线程池
  • React(8)-组件ref
  • 2022/8/30
  • picoCTF - Day 1 - Warm up
  • 前端面试题之组件
  • 自己动手写编译器:词法解析的系统化研究
  • 【程序员面试金典】01.02. 判定是否互为字符重排
  • ES6指北【2】—— 箭头函数
  • 【跃迁之路】【519天】程序员高效学习方法论探索系列(实验阶段276-2018.07.09)...
  • Elasticsearch 参考指南(升级前重新索引)
  • java正则表式的使用
  • Less 日常用法
  • Linux Process Manage
  • puppeteer stop redirect 的正确姿势及 net::ERR_FAILED 的解决
  • select2 取值 遍历 设置默认值
  • Webpack入门之遇到的那些坑,系列示例Demo
  • 阿里云Kubernetes容器服务上体验Knative
  • 等保2.0 | 几维安全发布等保检测、等保加固专版 加速企业等保合规
  • 对象引论
  • 分布式任务队列Celery
  • 区块链共识机制优缺点对比都是什么
  • 如何借助 NoSQL 提高 JPA 应用性能
  • 使用 Node.js 的 nodemailer 模块发送邮件(支持 QQ、163 等、支持附件)
  • 数组的操作
  • 用Canvas画一棵二叉树
  • 原创:新手布局福音!微信小程序使用flex的一些基础样式属性(一)
  • Java总结 - String - 这篇请使劲喷我
  • 如何正确理解,内页权重高于首页?
  • ​ 全球云科技基础设施:亚马逊云科技的海外服务器网络如何演进
  • ​Distil-Whisper:比Whisper快6倍,体积小50%的语音识别模型
  • #DBA杂记1
  • #Linux(帮助手册)
  • #调用传感器数据_Flink使用函数之监控传感器温度上升提醒
  • (1综述)从零开始的嵌入式图像图像处理(PI+QT+OpenCV)实战演练
  • (牛客腾讯思维编程题)编码编码分组打印下标题目分析
  • (原創) 如何將struct塞進vector? (C/C++) (STL)
  • (转)大道至简,职场上做人做事做管理
  • (转)利用PHP的debug_backtrace函数,实现PHP文件权限管理、动态加载 【反射】...
  • (最优化理论与方法)第二章最优化所需基础知识-第三节:重要凸集举例
  • .NET CORE 第一节 创建基本的 asp.net core
  • .net core MVC 通过 Filters 过滤器拦截请求及响应内容
  • .net core webapi Startup 注入ConfigurePrimaryHttpMessageHandler
  • .NET Core WebAPI中封装Swagger配置
  • .NET 指南:抽象化实现的基类
  • .NET建议使用的大小写命名原则
  • .so文件(linux系统)
  • /etc/fstab和/etc/mtab的区别