java分布式对象——远程方法中的参数和返回值+远程对象激活

【0】README

1)本文文字描述转自 core java volume 2, 旨在学习 java分布式对象——远程方法中的参数和返回值+远程对象激活 的相关知识;

【1】远程方法中的参数和返回值

1) 在开始进行远程方法调用时,调用参数需要从客户端的虚拟机中移动到服务器的虚拟机中。
2) 对于从一个虚拟机向另一个虚拟机传值,我们将其区分成两种情况:传递远程对象和传递非远程对象。


【1.1】传递远程对象

1)当一个对远程对象的引用从一个虚拟机传递到另一个虚拟机时,该远程对象的发送者和接收者都将持有一个对同一个实体的引用。这个引用并非是一个内存位置(内存位置在单个虚拟机内才有意义),而是由网络地址和该远程对象的唯一标识符构成的。这个信息给封装在存根对象中。

  • 1.1) 需要始终牢记的是: 在远程引用上的方法调用明显比在本地引用上的方法调用执行得慢,并且潜在地也更不可靠。

【1.2】传递非远程对象

Conclusion)总结一下,在虚拟机之间传递值有两种机制:

  • c1)实现了Remote接口: 的类的对象将作为远程引用传递;
  • c2)实现了Serializable接口: 但是没有实现Remote接口的类的对象将使用序列化进行复制;

Attention)

  • A1)这两种机制都是自动化的,而且不需要任何程序员的干预。
  • A2)请记住,序列化对于大型对象来说会比较慢,而且远程方法不能改变被序列化的参数。
  • A3)当然,你可以通过传递远程引用来避免这些问题。但是这么做代价太大: 在远程引用上调用方法与调用本地方法相比,代价高得多。
  • A4)意识到这些开销有助于在设计远程服务时进行选择。

1)看个荔枝: 我们的下一个示例程序将展示远程和可序列化对象的传递。我们将Warehouse接口修改为代码11-5的样子,如果给定关键词列表,这个仓库将返回最佳匹配的Product。

public interface Warehouse extends Remote
{
double getPrice(String description) throws RemoteException;
Product getProduct(List keywords) throws RemoteException;
} // getProduct方法的参数具有List类型。因此,参数值必须属于实现了List接口的可序列化的类,例如ArrayList。

Attention) Product类是可序列化的,服务器构建了一个Product对象,而客户端获取了它的一个副本(参见图11-7)。
这里写图片描述


【1.3】动态类加载

1)应用背景:关键词列表发送到了服务器,而且仓库也返回了Product类的一个实例。当然,客户端程序在编译时需要Product.class类文件。但是,只要我们的服务器程序无法找到关键词的匹配,它就会返回一件肯定让每个人都很高兴的产品:《Java核心技术》这本书。这个对象是Book类的实例,而Book类是Product的子类。
2)problem+solution:

  • 2.1)problem: 当客户端编译时,它也许从未看到过Book类。但是在运行时,它需要能够执行覆盖了Product方法的Book方法,这说明客户端需要拥有在运行时加载额外类的能力。
  • 2.2)solution: 客户端使用了与RMI注册表相同的机制,即类由web服务器提供服务,RMI服务器类将URL传递给客户端,客户端创建要求下载这些类的HTTP请求。

3)problem+solution:

  • 3.1)problem: 只要一个程序从网络位置加载新的代码,就会涉及安全问题。
  • 3.2)solution:正是由于这个原因,我们需要在动态加载类的RMI应用中使用安全管理器。

4) 安装安全管理器:使用RMI的程序应该安装一个安全管理器,去控制动态加载类的行为。可以用下面的指令安装:

System.setSecurityManager(new SecurityManager());

5)problem+solution:

  • 5.1)problem: 默认情况下,SecurityManager会限制程序中所有的代码去建立网络连接,但是,我们的程序需要建立到三个远程位置的网络连接(connection):

    • c1)加载远程类的Web服务器;
    • c2) RMI注册表;
    • c3)远程对象;
  • 5.2)solution:为了允许这些操作,需要提供一个策略文件。

  • 5.3)看个荔枝: 下面的策略文件允许一个应用建立任何到端口号至少为1024的某个端口的网络连接。(RMI端口默认为1099,远程对象使用的端口也大于等于1024。我们使用8080端口来下载类。)

    grant
    {
    permission java.net.SocketPermission
    “*:1024-65535”, “connect”;
    };


6)需要通过将java.security.policy属性设置为这个策略文件名,来指示安全管理器去读取该策略文件。
  • 6.1)可以使用下面这个调用:

    System.setProperty(“java.security.policy”, “rmi.policy”);

  • 6.2)或者,可以在命令行指定系统属性设置:

    -Djava.security.policy=rmi.policy

7)为了运行示范程序,请确保已经关闭了在前面的示范程序中启动的RMI注册表、Web服务器和服务器程序。打开四个控制台窗口,然后执行下面的步骤:

  • 7.1) 编译接口、实现、客户端和服务器类的源文件。
    javac *.java
  • 7.2) 创建三个目录:client、server和download,然后按下面这样组装它们:

    client/
    WarehouseClient.class
    Warehouse.class
    Product.class
    client.policy
    server/
    Warehouse.class
    Product.class
    Book.class
    WarehouseImpl.class
    WarehouseServer.class
    server.policy
    download/
    Warehouse.class
    Product.class
    Book.class

  • 7.3) 在第一个控制台窗口中,转到download目录下,启动NanoHTTP

  • 7.4) 在第二个控制台窗口中,转到server目录下,启动服务器: java -Djava.rmi.server.codebase=http://localhost:8080/ WarehouseServer
  • 7.5) 在第三个控制台窗口中,转到client目录下,运行客户端:

8)看个荔枝:
这里写图片描述
这里写图片描述

  • 远程对象传送全部源代码参见:https://github.com/pacosonTang/core-java-volume/tree/master/coreJavaAdvanced/chapter11/rmi_transfer

【1.4】具有多重接口的远程引用(远程类实现多个接口)

1)可以使用instanceof操作符来查看一个特定的远程对象是否实现了某个接口。假设我们通过一个类型为Warehouse的变量得到了一个远程对象:

Warehouse location = product.getLocation();

2)这个远程对象可能是一个服务中心,但也可能不是。要确定到底是不是,可以使用下面的测试:

if (location instanceof ServiceCenter)

3)如果测试通过,就可以将location转型为ServiceCenter,并调用getReturnAuthorization方法。


【1.5】远程对象与 equals,hashCode 和 clone 方法

1) 插入集中的对象必须覆写equals方法。如果是散列集或散列映射表,则需定义hashCode方法。
2)不能在远程接口中定义equals方法 和 hashCode 方法:然而,比较远程对象时有一个问题。如果要比较两个远程对象是否具有相同的内容,调用equals则必须联系包含这些对象的服务器,然后比较它们的内容。而该调用可能会失败。但是,Object类中的equals方法并未声明会抛出RemoteException异常,而远程接口中的所有方法都必须抛出该异常。因为子类的方法不能比它覆写的父类的方法抛出更多的异常,所以不能在远程接口中定义equals方法。hashCode也是这样。
3)存根对象的equals 方法 和 hashCode 方法: 相反,存根对象的equals和hashCode方法只是查看远程对象的位置。只要它们指向相同的远程对象,equals方法就认为两个存根相同。
Conclusion)总之,可以使用集与散列表中的远程引用,但是必须记住,对它们进行等价测试以及散列计算并不会考虑远程对象的内容。你不能直接克隆远程引用。


【2】 远程对象激活(延迟构造远程对象)

1)激活机制: 激活机制(activation)允许延迟构造远程对象,仅当至少有一个客户端调用远程对象上的远程方法时,才真正去构造该远程对象。 (干货——激活机制定义)
2)引用激活机制的client 和 server:

  • 2.1)client:要享用激活机制的好处,客户端代码完全无需改动。客户端只是简单的请求一个远程引用,然后通过它进行调用而已。
  • 2.2)server:然而,服务器程序则需由一个激活程序来代替。该程序构造了对象的激活描述符(activation descriptors),这样的对象可以延迟构造,并且该程序通过命名服务为远程方法调用绑定了接收者。第一次对这样的对象进行方法调用时,激活描述符中的信息将会用来构造该对象。

3)应用激活机制的远程对象: 必须继承Activatable类而不是UnicastRemoteObject类,当然,还需实现一个或多个远程接口。例如,

class WarehouseImpl
extends Activatable
implements Warehouse
{

}

4)因为对象的构造是延迟进行的,所以它必须以标准方式实现。因此,构造器必须包含以下两个参数(params):

  • p1)一个激活ID(只需传递给父类的构造器)
  • p2)一个包含所有构造信息的对象,包装为MarshalledObject;

  • 4.1)在构建激活描述符时,需要像下面这样从构造信息中构造一个MarshalledObject:
    MarshalledObject param = new MarshalledObject(constructionInfo);

  • 4.2)在实现对象的构造器中,使用MarshalledObject类的get方法来获得反序列化之后的构造信息:
    T constructionInfo = param.get();

5)看个荔枝:为了演示激活,我们修改了WarehouseImpl类,使得构造信息是一个由描述和价格构成的映射表。这个信息被包装到了MarshalledObject中,并且在构造器中被拆包出来:

public WarehouseImpl(ActivationID id, MarshalledObject<Map<String, Double>> param)
throws RemoteException, ClassNotFoundException, IOException
{
super(id, 0);
prices = param.get();
System.out.println("Warehouse implementation constructed.");
}
  • 5.1)将0作为父类构造器的第二个参数: 代表RMI类库应该分配一个合适的端口号作为监听端口。构造器会打印一个信息,这样就可以看到所需的产品对象已经被激活了。
  • Attention) 其实远程对象不是一定要继承Activatable类,例如,可以将下面的静态方法调用放在服务器类的构造器中。

    Activatable.exportObject(this, id, 0)


6)如何构建激活程序
  • step1)需要定义一个激活组。一个激活组描述了启动远程对象所在的虚拟机所需的公共参数,其中最重要的参数是安全策略。
  • step2) 然后如下构造一个激活组描述符:

    Properties props = new Properties();
    props.put(“java.security.policy”, “/server/server.policy”);
    ActivationGroupDesc group = new ActivationGroupDesc(props, null);
    //第二个参数描述了一个特殊的命令选项,在这个例子中不需要任何选项,所以我们传递了一个null引用。

  • step3)创建一个组ID
    ActivationGroupID id = ActivationGroup.getSystem().registerGroup(group

  • step4) 构造一个激活描述符了。对于需要构造的每一个对象,都应该包括以下内容(contents):

    • c1)激活组ID,对象将在与其对应的虚拟机上被构造;
    • c2)类的名字(例如”ProductImpl”或”com.mycompany.MyClassImpl”);
    • c3) URL字符串,由该URL加载类文件。这应该是基本URL,不含包的路径;
    • c4)编组后的构造信息。

7)看个荔枝:

MarshalledObject param = new MarshalledObject(constructionInfo);
ActivationDesc desc = new ActivationDesc(id, “WarehouseImpl”,
“http://myserver.com/download/“, param);

  • 7.1)将此描述符传递给静态的Activatable.register方法。它返回一个对象,该对象实现了实现类的远程接口。可以使用命名服务绑定该对象:

    Warehouse centralWarehouse = (Warehouse) Activatable.register(desc);
    namingContext.bind(“rmi:central_warehouse”, centralWarehouse);

  • Attention) 与前例的服务器程序不同,激活程序在注册与绑定激活接收者之后就会退出。仅当远程方法调用第一次发生时,才会构造远程对象。

8)荔枝:

  • 8.1)启动远程对象激活程序,可按一下steps 进行:

    • step1) 编译所有文件;
    • step2)发布类文件:

      client/
              WarehouseClient.class
              Warehouse.class
      server/
               WarehouseActivator.class
               Warehouse.class
               WarehouseImpl.class
               server.policy
      download/
               Warehouse.class
               NanoHTTPD.java
      rmi/
               rmid.policy

    • step3)启动RMI注册表
      这里写图片描述

    • step4)在rmi目录中启动 RMI激活守护程序

      rmid -J-Djava.security.policy=rmid.policy
      rmid程序监听激活请求,并且激活另一个虚拟机中的对象。要启动一个虚拟机,rmid 程序需要一定的权限。这些权限都在一个策略文件中说明了。使用-J, 可以传递一个选项给运行激活守护程序的虚拟机;
      这里写图片描述

    • step5)在download 目录中启动NanoHTTPD Web 服务器;
      这里写图片描述

    • step6) 从server目录运行激活程序
      java -Djava.rmi.server.codebase=http://localhost:8080/ WarehouseActivator
      这里写图片描述

    • step7) 从client目录运行客户端程序;
      这里写图片描述

Attention) 上述结果是可以正确查找远程对象,但是当调用Warehouse接口的实现类的getPrice 方法的时候,却抛出了异常,搞了一下午,我确实无能为力了,先留在这里,以后有机会再来解决。。

  • 相关命令行指令如下:
rmid -J-Djava.security.policy=rmid.policy
java com.corejava.chapter11.activation.download.NanoHTTPDMain
java -Djava.rmi.server.codebase=http://localhost:8080/ com.corejava.chapter11.activation.server.WarehouseActivator

这里写图片描述

  • for full source code, please visit https://github.com/pacosonTang/core-java-volume/tree/master/coreJavaAdvanced/chapter11/activation

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/331400.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

wcf:rest_REST:管理多对多关系

wcf:rest介绍 管理多个资源之间的关系可能是RESTful API的重要组成部分。 在这篇文章中&#xff0c;我们将看到使用REST API可以管理多对多关系。 我们以一个简单的用户 / 组关系为例。 假设用户和组是两个单独的资源&#xff08;例如/ users和/ groups &#xff09;&#xff…

java安全——类加载器+字节码校验+安全管理器与访问权限

【0】README 0.1&#xff09;本文文字描述转自 core java volume 2&#xff0c;旨在学习 java安全 的相关知识&#xff1b; 【1】类加载器 1&#xff09;java 技术提供了以下3种确保安全的机制&#xff08;mechanism&#xff09;&#xff1a; m1&#xff09;语言设计特性&am…

Tomcat的web项目部署方式

一、host配置Context 在tomcat中的conf目录中&#xff0c;在server.xml中的&#xff0c;<host/>节点中添加&#xff1a; <Context path"/app" docBase"D:/myeclipse/firstapp/WebRoot" debug"0" privileged"true" reloadab…

java.rmi.UnmarshalException:errorunmarshalling return; java.lang.ClassNotFoundException的解决方法

1&#xff09;problem 出现 java.rmi.UnmarshalException: error unmarshalling return; nested exception is: java.lang.ClassNotFoundException 异常的原因是&#xff0c;在命令行执行 rmiregistry&#xff0c;并没有指定好 绑定时查找的类文件的路径。 …

javafx 图标_JavaFX技巧32:需要图标吗? 使用Ikonli!

javafx 图标动机 自2013年以来&#xff0c;我一直在编写JavaFX应用程序和库的代码&#xff0c;它们的共同点是&#xff0c;我需要找到可以用于它们的良好图标/图形。 作为前Swing开发人员&#xff0c;我首先使用图像文件&#xff0c;GIF或PNG。 通常&#xff0c;我会从IconExpe…

java安全 ——JAAS(Java 认证和授权服务)开发指南

以下内容转自&#xff1a; http://lyb520320.iteye.com/blog/720478【0】README1&#xff09;本文翻译自&#xff1a;http://java.sun.com/developer/technicalArticles/Security/jaasv2/2&#xff09;传统的JAVA安全机制没有提供必要的架构支持传统的认证和授权&#xff1b;在…

aws dynamodb_AWS Lambda将数据保存在DynamoDB中

aws dynamodb在本教程中&#xff0c;我们将看到如何使用AWS Lambda将数据保存在Dynamo DB中。 这是必需的步骤&#xff1a; – 在Dynamo数据库中创建一个名为Employee的表 –创建一个AWS Lambda函数&#xff0c;该函数可以使用Dynamo DB中的Employee POJO保存员工的名字和姓…

Tomcat处理一个HTTP请求的过程

一、Tomcat的组成 &#xff08;1&#xff09;Server服务器元素代表整个catalina servlet容器。是单例模式。 &#xff08;2&#xff09;ServiceService是这样一个集合&#xff1a;它由一个或者多个Connector组成&#xff0c;以及一个Engine&#xff0c;负责处理所有Connector所…

java安全——数字签名+代码签名

【0】README1&#xff09;本文文字描述转自 core java volume 2, 旨在学习 java安全——数字签名 的基础知识&#xff1b;2&#xff09;本文实践内容以及截图笔记均为原创&#xff1b;3&#xff09;如果要给予applet更多的信赖&#xff0c;你必须知道下面两件事&#xff1a; 3.…

//rest风格写_REST /使用提要发布事件

//rest风格写处理事件 当使用多个解耦的服务时&#xff08;例如&#xff0c;在微服务体系结构中 &#xff09;&#xff0c;很有可能需要一种方法来将某种域事件从一个服务发布到一个或多个其他服务。 许多广泛采用的解决方案依赖于单独的基础结构来解决此问题&#xff08;例如…

Java IO总结

一、IO的类型 面向字节的流&#xff0c;面向字符的流二、面向字节的流 &#xff08;1&#xff09;InputStream FileInputStream FilterInputStream -BufferedInputStream -DataInputStream -PushbackInputStream 回退流 unread() ObjectInputStream PipedInputSt…

java安全——加密

【0】README1&#xff09;本文文字描述转自 core java volume 2&#xff0c;旨在学习 java安全——加密 的基础知识&#xff1b;2&#xff09;java 安全性的第二个重要方面是加密。3&#xff09;认证对于代码签名已足够了-没必要将代码隐藏起来。但是&#xff0c;当applet或者应…

java 异常 最佳实践_处理Java异常的10种最佳实践

java 异常 最佳实践在本文中&#xff0c;我们将看到处理Java异常的最佳实践。 用Java处理异常不是一件容易的事&#xff0c;因为新手很难理解&#xff0c;甚至专业的开发人员也可能浪费时间讨论应该抛出或处理哪些Java异常。 因此&#xff0c;最大的开发公司对如何使用它们有一…

Java NIO总结

一、NIO NIO是new IO&#xff0c;也是非阻塞IO。有Channel、Selector、Buffer、Pipe、FileLock等类。 Buffer在java.nio包 Channel、Selector、Pipe、FileLock等在java.nio.channels包 二、Channel通道 设置非阻塞configureBlocking(false); 注册选择器register(selector,…

java 不可变map_如何用Java创建不可变的Map

java 不可变map你好朋友&#xff0c; 在本教程中&#xff0c;我们将看到如何在Java中创建不可变的Map。 –不可变的类或对象是什么意思&#xff1f; –什么是不可变地图&#xff1f; –如何在Java中创建不可变的Map&#xff1f; 不变的类或对象是什么意思&#xff1f; 不可…

ToolProvider.getSystemJavaCompiler() return null 的解决方法

【1】利用java 编译器API 编译 普通的java文件 1.1&#xff09;代码如下&#xff1a; package com.corejava.chapter10_2;import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.OutputStream;import javax.tools.JavaCompiler; import jav…

脚本错误和安全警报怎么解决_适用于应用程序错误的AWS警报

脚本错误和安全警报怎么解决监视对于任何实际应用都是关键的。 您必须知道正在发生的事情&#xff0c;并在发生问题时实时得到警报。 AWS为此提供了CloudWatch&#xff0c;并自动为您提供了许多指标。 但是&#xff0c;您必须定义一些自己的东西。 然后&#xff0c;您需要定义适…

java平台脚本+java编译器API

【0】README 0.1&#xff09;本文文字描述转自 core java volume 2&#xff0c; 旨在学习 java平台脚本java编译器API 的 基础知识&#xff1b; ------------------------------------------------------------------------------ 【1】java平台的脚本 1&#xff09;脚本语…

Java 多线程总结

一、多线程实现方式 &#xff08;1&#xff09;继承Thread类&#xff0c;覆盖run方法 &#xff08;2&#xff09;实现Runnable接口&#xff0c;覆盖run方法&#xff0c;将对象传人Thread对象中实现Runnable接口比继承Thread类所具有的优势&#xff1a; 1&#xff09;适合多个相…

古巴比伦乘法_古巴:为生产做准备

古巴比伦乘法“它可以在我的本地机器上运行&#xff01;” 如今&#xff0c;它听起来像模因&#xff0c;但是“开发环境与生产环境”的问题仍然存在。 作为开发人员&#xff0c;您应始终牢记&#xff0c;您的应用程序有一天将在生产环境中开始运行。 在本文中&#xff0c;我们将…