JavaRMI与CORBA技术详解
立即解锁
发布时间: 2025-08-20 00:52:11 订阅数: 12 

### Java RMI与CORBA技术详解
在Java网络编程领域,RMI(Remote Method Invocation)和CORBA(Common Object Request Broker Architecture)是两项重要的技术,它们为分布式系统的开发提供了强大的支持。下面将详细介绍这两项技术的相关内容。
#### RMI技术及安全问题
RMI是一种用于在分布式系统中实现对象远程调用的机制,它允许Java对象在不同的Java虚拟机(JVM)之间进行通信和交互。然而,RMI在使用过程中存在一定的安全隐患,特别是当客户端需要从远程位置加载类文件时。
##### RMI安全机制
当客户端和服务器进程可以直接访问相同的类文件时,通常不需要采取特殊的安全措施。但如果客户端接收到一个没有对应类文件的对象,它可能会尝试从远程位置加载该类文件并在其JVM中实例化对象。这种情况下,从远程源作为RMI参数传递的对象在反序列化时可能会立即在客户端机器上启动执行,而用户或程序员却没有进行任何操作,这就可能导致安全漏洞。
为了避免这种安全问题,Java使用`SecureClassLoader`对象来处理类文件的加载,并且必须为其定义安全限制。`java.policy`文件定义了这些安全限制,而`java.security`文件定义了安全属性。安全策略的实现由`RMISecurityManager`类的对象控制,它是`SecurityManager`的子类,会创建类似于管理小程序的“沙箱”规则。如果没有这样的对象,Java应用程序甚至不会尝试加载非本地文件系统中的类。
##### 自定义安全管理器
虽然可以使用Java实用工具`policytool`来修改安全策略,但这只能针对单个主机进行,因此编写和安装自己的安全管理器可能更为直接。默认的`RMISecurityManager`依赖于系统的默认安全策略,该策略过于严格,不允许从远程站点下载类文件。为了解决这个问题,我们需要创建一个扩展`RMISecurityManager`的自定义安全管理器,并为`checkPermission`方法提供定义。以下是一个最简单的安全管理器示例,它允许所有操作:
```java
import java.rmi.*;
import java.security.*;
public class ZeroSecurityManager extends RMISecurityManager {
public void checkPermission(Permission permission) {
System.out.println("checkPermission for : " + permission.toString());
}
}
```
这个安全管理器文件必须使用`javac`进行编译。客户端程序需要通过调用`System`类的静态方法`setSecurityManager`来安装这个类的对象,该方法接受一个`SecurityManager`类(或其子类)的参数。以下是包含调用`setSecurityManager`的`HelloClient`程序示例:
```java
import java.rmi.*;
public class HelloClient {
private static final String HOST = "localhost";
public static void main(String[] args) {
if (System.getSecurityManager() == null) {
System.setSecurityManager(new ZeroSecurityManager());
}
try {
Hello greeting = (Hello)Naming.lookup("rmi://" + HOST + "/Hello");
System.out.println("Message received: " + greeting.getGreeting());
} catch(ConnectException conEx) {
System.out.println("Unable to connect to server!");
System.exit(1);
} catch(Exception ex) {
ex.printStackTrace();
System.exit(1);
}
}
}
```
在执行服务器时,需要指定所需的`.class`文件的位置,以便客户端可以下载它们。这可以通过使用`-D`命令行选项来设置`java.rmi.server.codebase`属性来实现。例如,如果文件位置的URL是`http://java.shu.ac.uk/rmi/`,则可以使用以下命令启动`HelloServer`程序并设置代码库属性:
```
java -Djava.rmi.server.codebase=http://java.shu.ac.uk/rmi/ HelloServer
```
##### RMI练习
为了更好地理解RMI的使用,下面给出两个练习:
- **练习5.1**:使用`Result`类并进行小修改以确保该类的对象可序列化,通过RMI接口使`getResults`方法可用。该方法应返回一个包含已初始化`Result`对象的`ArrayList`,这些对象由服务器程序设置并通过服务器放置在RMI注册表中的实现对象提供。服务器应在实现对象包含的`ArrayList`中存储两个`Result`对象。通过客户端程序访问该实现对象,并使用`Result`类的方法显示两个`Result`对象的姓氏和考试成绩。
```java
class Result implements java.io.Serializable {
private String surname;
private int mark;
public Result(String name, int score) {
surname = name;
mark = score;
}
public String getName() {
return surname;
}
public void setName(String name) {
surname = name;
}
public int getMark() {
return mark;
}
public void setMark(int score) {
if ((score >= 0) && (score <= 100)) {
mark = score;
}
}
}
```
- **练习5.2**:重复上述练习,但这次不使用单独的`Result`类,而是将结果方法直接包含在实现类中。将实现对象远程存储在名为`result1`和`result2`的位置。通过客户端程序访问这些对象,并使用实现类的方法显示两个对象的姓氏和考试成绩。
#### CORBA技术介绍
虽然RMI是一种强大的机制,可在平台独立的方式下分布和处理对象,但它有一个显著的缺点,即只能与使用Java创建的对象一起工作。在现实世界中,软件对象可能使用多种编程语言创建,因此需要一种更通用的方法来开发分布式系统,CORBA应运而生。
##### CORBA背景和基础
CORBA是对象管理组(OMG)的产品,OMG是一个由800多家公司组成的联盟,涵盖了大部分IT行业(微软除外),致力于定义和推广对象技术的行业标准。CORBA的第一个版本于1991年推出,目前的版本(截至撰写本文时)是3.3,于2012年11月发布。
CORBA不是一个具体的实现,而是一个用于创建和使用分布式对象的规范。该规范的单个实现构成一个对象请求代理(ORB),目前市场上有多种这样的实现。Java IDL(接口定义语言)是Java SE(从J2SE 1.2起)的核心包之一,也是本文所有示例将使用的ORB。与RMI ORB使用的JRMP(Java Remote Method Protocol)不同,CORBA ORB使用基于TCP/IP的IIOP(Internet Inter-Orb Protocol),这使得不同供应商的ORB之间能够实现互操作性。
另一个RMI和CORBA的根本区别在于,RMI使用Java来定义其对象的接口,而CORBA使用一种特殊的语言——接口定义语言(IDL)来定义这些接口。虽然这种语言在语法上与C++相似,但它不是一种完整的编程语言。为了让任何ORB能够访问特定编程语言中的软件对象,ORB必须提供从IDL到目标语言的映射。目前指定的映射包括Java、C++、C、Smalltalk、COBOL和Ada。
在CORBA交互的客户端,每个要远程调用的方法都有一个代码存根(stub),它作为远程方法的代理。在服务器端,有骨架代码(skeleton),它也作为所需方法的代理,用于将传入的方法调用和任何参数转换为其特定于实现的格式,然后用于在关联对象上调用方法实现。方法调用通过客户端的存根,然后通过ORB,最后通过服务器端的骨架,在对象上执行。以下是客户端和服务器使用相同ORB时的远程方法调用流程:
```mermaid
graph LR
classDef process fill:#E5F6FF,stroke:#73A6FF,stroke-width:2px;
A(Client):::process --> B(IDL stub):::process
B --> C(ORB):::process
C --> D(IDL skeleton):::process
D --> E(Object implementation):::process
A -.->|Request| E
```
##### Java IDL规范结构
Java IDL包括一个符合OMG标准的IDL版本以及从该IDL到Java的相应映射。`Java IDL`这个名称可能会引起一些不必要的混淆,它似乎暗示该产品仅包含一个IDL,但实际上,它通常指的是ORB本身,包括IDL到Java的映射。
IDL支持类层次结构,其根是`Object`类,但这与Java语言的`Object`类不同,在Java中它被标识为`org.omg.CORBA.Object`,是`java.lang.Object`的子类。一些CORBA操作(如名称查找)返回`org.omg.CORBA.Object`类的对象,必须显式地将其“缩小”(有效地转换为更具体的类),这可以通过使用`idlj`编译器生成的“帮助器”类来实现。
IDL规范包含在后缀为`.idl`的文件中。该文件的周围结构通常是一个模块(module),也可以是一个接口(interface),它对应于Java中的包,并在编译IDL时会生成Java的`package`语句。模块声明以关键字`module`开头,后跟特定模块的名称(即使Java约定包名以小写字母开头,模块名也通常以大写字母开头)。模块声明的主体用花括号括起来,并且像C++一样,以分号结尾。以下是一个名为`Sales`的模块的顶级结构示例:
```idl
module Sales {
// 模块内容
};
```
在模块主体内,会有一个或多个接口声明,每个接口对应于服务器上的一个应用类,并且以关键字`interface`开头,后跟接口的名称。当IDL被编译时,每个语句将生成一个Java的`interface`语句。接口声明的主体用花括号括起来,指定了要向客户端公开的数据属性和操作的签名。每个数据属性的声明语法如下:
```idl
attribute <type> <name>;
```
例如:
```idl
attribute long total;
```
默认情况下,这个属性将是一个“读写”属性,在编译IDL文件时将自动映射到一对Java访问器和修改器方法(“get”和“set”)。但这些方法不包含“get”和“set”或任何等效动词,而是与它们的(名词)属性具有相同的名称。对于上述示例,访问器和修改器方法的签名如下:
```java
int total(); // 访问器
void total(int i); // 修改器
```
如果希望将属性设为只读(即不可修改),可以使用`readonly`修饰符,例如:
```idl
readonly attribute long total;
```
这样,在编译文件时只会创建访问器方法。
以下是IDL中可用的基本类型及其对应的Java类型的表格:
| IDL类型 | Java类型 |
| ---- | ---- |
| boolean | boolean |
| char和wchar | char |
| octet | byte |
| string和wstring | String |
| short | short |
| long | int |
| long long | long |
| double | double |
| fixed | java.math.BigDecimal |
在每个操作签名中,返回类型可用的基本类型与上述相同,但增加了`void`。`short`、`long`和`long long`类型也可以在前面加上`unsigned`限定符,但这不会影响它们的映射目标。`const`限定符也可以使
0
0
复制全文
相关推荐










