- 浏览: 103522 次
- 性别:
- 来自: 深圳
文章分类
最新评论
-
chifanbua:
我基本上在iteye上很少留言的 不过你的这个写的确实不错 用 ...
Oracle decode函数说明 -
shaoxuexue86:
谢谢啊
RMI 开发步骤 -
huxiaojun_198213:
RMIRegistHelper只是负责注册远程对象,与客户端所 ...
RMI 开发步骤 -
shaoxuexue86:
请问客户端程序ClientTest 与 RMIRegistHe ...
RMI 开发步骤 -
huxiaojun_198213:
本章节可能有一些细节方面翻译得不是很好,有出入的地方,还请各 ...
RMI动态类加载
Implementing a Remote Interface
This section discusses the task of implementing a class for the compute engine. In general, a class that implements a remote interface should at least do the following:
实现一个远程接口
这个章节讨论计算引擎的实现类。一般来说,实现一个远程接口的类至少应该遵循以下规则:
•Declare the remote interfaces being implemented
•Define the constructor for each remote object
•Provide an implementation for each remote method in the remote interfaces
•定义一个用于实现的远程接口
•为每个远程对象定义构造函数
•实现远程接口中定义的每一个远程方法
An RMI server program needs to create the initial remote objects and export them to the RMI runtime, which makes them available to receive incoming remote invocations. This setup procedure can be either encapsulated in a method of the remote object implementation class itself or included in another class entirely. The setup procedure should do the following:
一个RMI服务器端程序需要创建最初的远程对象,并把这些远程对象导出到RMI的运行时环境中,这些运行时环境使得它们可以接收到远程调用.这个设置过程可以封装在远程对象的方法中,也可以完全包含在另一个类里。此设置过程如下:
•Create and install a security manager
•Create and export one or more remote objects
•Register at least one remote object with the RMI registry (or with
another naming service, such as a service accessible through the Java Naming and Directory Interface) for bootstrapping purposes
The complete implementation of the compute engine follows. The engine.ComputeEngine class implements the remote interface Compute and also includes the main method for setting up the compute engine.
•创建和安装一个安全管理器
•创建和导出一个或多个远程对象
•至少在RMI registry(或另外的命名与目录接口)中注册一个远程对象。engine.ComputeEngine类实现了Compute远程接口,同时也在main方法中设置了计算引擎。
Here is the source code for the ComputeEngine class:
以下是ComputeEngine类的源代码:
The following sections discuss each component of the compute engine implementation.
接下来的部分将讨论计算引擎实现类的各个组成部分。
Declaring the Remote Interfaces Being Implemented
The implementation class for the compute engine is declared as follows:
实现计算引擎的实现声明如下:
This declaration states that the class implements the Compute remote interface and therefore can be used for a remote object.
这个声明表明实现远程接口Compute的类可以用作远程对象。
The ComputeEngine class defines a remote object implementation class that implements a single remote interface and no other interfaces. The ComputeEngine class also contains two executable program elements that can only be invoked locally. The first of these elements is a constructor for ComputeEngine instances. The second of these elements is a main method that is used to create a ComputeEngine instance and make it available to clients.
ComputeEngine类只定义了实现了一个远程接口的远程对象。同时它也包含两个只能用于本地调用的方法。第一个是用于构建ComputeEngine的构造函数。第二个是main方法,用于创建ComputeEngine实例并使其对于客户端可用。
Defining the Constructor for the Remote Object
The ComputeEngine class has a single constructor that takes no arguments. The code for the constructor is as follows:
定义远程对象的构造函数,ComputeEngine类只有一个无参的构造函数,其声明如下:
This constructor just invokes the superclass constructor, which is the no-argument constructor of the Object class. Although the superclass constructor gets invoked even if omitted from the ComputeEngine constructor, it is included for clarity.
这个构造函数调用了超类的无参构造函数。尽管超类的构造函数即便在ComputeEngine构造函数中省略的情况下也能得到调用,但还是应该明确调用。
Providing Implementations for Each Remote Method
The class for a remote object provides implementations for each remote method specified in the remote interfaces. The Compute interface contains a single remote method, executeTask, which is implemented as follows:
为每个远程方法提供实现
远程对象类实现了远程接口中指定的每一个远程方法。Compute接口仅含有一个远程方法executeTask,其具体实现如下:
This method implements the protocol between the ComputeEngine remote object and its clients. Each client provides the ComputeEngine with a Task object that has a particular implementation of the Task interface's execute method. The ComputeEngine executes each client's task and returns the result of the task's execute method directly to the client.
这个方法实现了ComputeEngine远程对象和它的客户端之间的协议。每个客户端提供了Task接口的execute方法的具体实现。ComputeEngine执行每个客户端任务并将其结果直接返回给客户端。
Passing Objects in RMI
Arguments to or return values from remote methods can be of almost any type, including local objects, remote objects, and primitive data types. More precisely, any entity of any type can be passed to or from a remote method as long as the entity is an instance of a type that is a primitive data type, a remote object, or a serializable object, which means that it implements the interface java.io.Serializable.
在RMI中传递对象
远程方法的参数或返回值几乎可以是任何数据类型,包括本地对象,远程对象以及原始类型。
更准确地说,任何类型的任何实体都可以作为远程方法的参数或返回值,只要这个实体是原始数据类型,远程对象或实现了java.io.Serializable接口的序列化对象的实例.
Some object types do not meet any of these criteria and thus cannot be passed to or returned from a remote method. Most of these objects, such as threads or file descriptors, encapsulate information that makes sense only within a single address space. Many of the core classes, including the classes in the packages java.lang and java.util, implement the Serializable interface.
如果某个对象不满足上述条件中的任何一个,就不能作为远程方法的参数或返回值。比如线程或文件描述,就不能作为远程方法的参数和返回值。许多核心类,包括java.lang 和java.util包中的类都实现了Serializable接口。
The rules governing how arguments and return values are passed are as follows:
参数和返回值是通过以下规则确定的:
•Remote objects are essentially passed by reference. A remote object reference is a stub, which is a client-side proxy that implements the complete set of remote interfaces that the remote object implements.
•Local objects are passed by copy, using object serialization. By default, all fields are copied except fields that are marked static or transient. Default serialization behavior can be overridden on a class-by-class basis.
Passing a remote object by reference means that any changes made to the state of the object by remote method invocations are reflected in the original remote object. When a remote object is passed, only those interfaces that are remote interfaces are available to the receiver. Any methods defined in the implementation class or defined in non-remote interfaces implemented by the class are not available to that receiver.
•远程对象本质是通过引用来传递的。一个远程对象的引用是一个stub(存根),stub是一个完全实现了远程接口的客户端代理。
•本地对象是通过拷贝来传递的,使用的是对象序列化。默认情况下,除了标记为static,transient的字段都会被拷贝。默认的序列化行可以通过基于class-by-class的方式进行覆盖。
通过引用来传递远程对象,意味着被远程方法调用的对象状态的任何修改都会反映到原来的远程对象上。当远程对象被传递时,只有那些远程接口对于接收者(客户端)是有效的。任何定义在实现类的方法或定义在实现非远程接口中的方法对于客户端来说都是无效的。
For example, if you were to pass a reference to an instance of the ComputeEngine class, the receiver would have access only to the compute engine's executeTask method. That receiver would not see the ComputeEngine constructor, its main method, or its implementation of any methods of java.lang.Object.
比如,如果我们传递一个引用给ComputeEngine类的实例,那么接收者只能访问计算引擎的executeTask方法。那个接收者不能看到ComputeEngine的构造方法,main方法或者java.lang.Object任何方法的实现。
In the parameters and return values of remote method invocations, objects that are not remote objects are passed by value. Thus, a copy of the object is created in the receiving Java virtual machine. Any changes to the object's state by the receiver are reflected only in the receiver's copy, not in the sender's original instance. Any changes to the object's state by the sender are reflected only in the sender's original instance, not in the receiver's copy.
在远程方法调用的参数和返回值中,非远程对象的传递是通过值的方式来进行的。因此,对象的拷贝将会在接收的JVM被创建。被接收者修改的任何对象状态的改变只能反映在接收者的拷贝中,而不反映在发送者的原始实例中。被发送者修改的任何对象状态的改变只能反映在发送者的原始实例中,而不反映在接收者的拷贝中。
Implementing the Server's main Method
The most complex method of the ComputeEngine implementation is the main method. The main method is used to start the ComputeEngine and therefore needs to do the necessary initialization and housekeeping to prepare the server to accept calls from clients. This method is not a remote method, which means that it cannot be invoked from a different Java virtual machine. Because the main method is declared static, the method is not associated with an object at all but rather with the class ComputeEngine.
实现服务器的main方法
ComputeEngine实现最复杂的部分便是main方法。此方法用于启动ComputeEngine,因此需要作必要的初始化和准备工作以便接受客户端的调用。此方法不是远程方法,这意味着它不能被不同的JVM所调用。因为main方法被声明为static的,因此它与ComputeEngine类相关的,而不是与ComputeEngine的实例相关的。
Creating and Installing a Security Manager
The main method's first task is to create and install a security manager, which protects access to system resources from untrusted downloaded code running within the Java virtual machine. A security manager determines whether downloaded code has access to the local file system or can perform any other privileged operations.
创建和初始化安全管理器
main方法的第一个任务是创建和安装一个安全管理器,其目的是防止运行在JVM中的下载的不可信任的代码访问系统资源。安全管理器将决定下载的代码能否访问本地文件系统或执行其他有特权的操作。
If an RMI program does not install a security manager, RMI will not download classes (other than from the local class path) for objects received as arguments or return values of remote method invocations. This restriction ensures that the operations performed by downloaded code are subject to a security policy.
如果一个RMI程序没有安装安全管理器,RMI将不会为了远程方法调用的参数和返回值下载字节码(除了那些来自本地类路径的类外)。这种限制保证下载代码执行的操作符合安全策略。
Here's the code that creates and installs a security manager:
以下是创建和安装安全管理器的代码:
Making the Remote Object Available to Clients
Next, the main method creates an instance of ComputeEngine and exports it to the RMI runtime with the following statements:
使远程对象对客户端可用
下一步,main方法创建了一个ComputeEngine的实例,并使用以下语句将它导出到RMI运行时环境:
The static UnicastRemoteObject.exportObject method exports the supplied remote object so that it can receive invocations of its remote methods from remote clients. The second argument, an int, specifies which TCP port to use to listen for incoming remote invocation requests for the object. It is common to use the value zero, which specifies the use of an anonymous port. The actual port will then be chosen at runtime by RMI or the underlying operating system. However, a non-zero value can also be used to specify a specific port to use for listening. Once the exportObject invocation has returned successfully, the ComputeEngine remote object is ready to process incoming remote invocations.
UnicastRemoteObject.exportObject静态方法用于导出远程对象,以便能被远程客户端的远程方法调用。第二个整形参数,用于指定监听远程调用的TCP端口.通常情况下,它使用0,表示使用一个匿名端口,实际端口将通过RMI在运行时指定或由底层操作系统指定。而对于非0的端口,将被用作监听的特定端口。一旦exportObject调用成功返回,ComputeEngine远程对象就开始准备好处理到来的远程调用。
The exportObject method returns a stub for the exported remote object. Note that the type of the variable stub must be Compute, not ComputeEngine, because the stub for a remote object only implements the remote interfaces that the exported remote object implements.
exportObject方法返回一个已导出的远程对象的存根。注意,stub变量的类型必须是Comute接口,而不是ComuteEngine,因为远程对象的stub只实现了导出的远程对象实现的远程接口。
The exportObject method declares that it can throw a RemoteException, which is a checked exception type. The main method handles this exception with its try/catch block. If the exception were not handled in this way, RemoteException would have to be declared in the throws clause of the main method. An attempt to export a remote object can throw a RemoteException if the necessary communication resources are not available, such as if the requested port is bound for some other purpose.
exportObject方法能抛出一个RemoteException,它是一个受查异常。main方法通过try/catch语句块来处理这个异常。如果异常不以这种方式处理,main方法就应该将其抛出。地导出一个远程对象的时候,如果因为必要的通信资源不可用,那么将会抛出RemoteException。比如请求的端口由于其他目的而被占用。
Before a client can invoke a method on a remote object, it must first obtain a reference to the remote object. Obtaining a reference can be done in the same way that any other object reference is obtained in a program, such as by getting the reference as part of the return value of a method or as part of a data structure that contains such a reference.
在一个客户端能调用远程对象的方法前,它必须首先获得远程对象的引用。
The system provides a particular type of remote object, the RMI registry, for finding references to other remote objects. The RMI registry is a simple remote object naming service that enables clients to obtain a reference to a remote object by name. The registry is typically only used to locate the first remote object that an RMI client needs to use. That first remote object might then provide support for finding other objects.
系统提供了远程对象的特别类型,RMI registry,用于查找其他远程的引用。RMI registry是一个简单的远程对象命名服务,它使得客户端能够通过名字获取到远程对象的引用。registry典型地用于定位RMI客户端要用到的第一个远程对象。第一个远程对象然后为查找其他对象提供支持。
The java.rmi.registry.Registry remote interface is the API for binding (or registering) and looking up remote objects in the registry. The java.rmi.registry.LocateRegistry class provides static methods for synthesizing a remote reference to a registry at a particular network address (host and port). These methods create the remote reference object containing the specified network address without performing any remote communication. LocateRegistry also provides static methods for creating a new registry in the current Java virtual machine, although this example does not use those methods. Once a remote object is registered with an RMI registry on the local host, clients on any host can look up the remote object by name, obtain its reference, and then invoke remote methods on the object. The registry can be shared by all servers running on a host, or an individual server process can create and use its own registry.
java.rmi.registry.Registry远程接口是用于在注册机中注册和查找远程对象的应用程序编程接口。java.rmi.registry.LocateRegistry类提供了静态方法来从实际的网络地址(主机和端口)获取远程引用。这些方法根据指定的网络地址,不执行任何远程通信来创建远程引用对象。同时LocateRegistry也提供静态方法在当前JVM中创建一个新的registry,尽管这个示例中没有用到这些方法。一旦一个远程对象注册到本地RMI registry中,在任何主机上的客户端都能通过名字查找到远程对象,获取它的引用,然后调用对象上的方法。registry能够被运行在一台主机的所有服务器所共享,也可以用一台单独的服务来创建和使用它自己的registry.
The ComputeEngine class creates a name for the object with the following statement:
ComputeEngine使用下面的语句来为对象创建一个名字:
The code then adds the name to the RMI registry running on the server. This step is done later with the following statements:
然后代码将此名字加到正在服务端运行的RMI registry中。这个步骤是通过以下语句完成的。
This rebind invocation makes a remote call to the RMI registry on the local host. Like any remote call, this call can result in a RemoteException being thrown, which is handled by the catch block at the end of the main method.
Note the following about the Registry.rebind invocation:
•The no-argument overload of LocateRegistry.getRegistry synthesizes a reference to a registry on the local host and on the default registry port, 1099. You must use an overload that has an int parameter if the registry is created on a port other than 1099.
无参的重载方法LocateRegistry.getRegistry将会在本地主机和缺省端口1099中得到一个registry的引用。如果创建registry的端口不是1099,你可以使用重载的带int参数的方法。
•When a remote invocation on the registry is made, a stub for the remote object is passed instead of a copy of the remote object itself. Remote implementation objects, such as instances of ComputeEngine, never leave the Java virtual machine in which they were created. Thus, when a client performs a lookup in a server's remote object registry, a copy of the stub is returned. Remote objects in such cases are thus effectively passed by (remote) reference rather than by value.
当一个远程调用在registry中发生的时候,为远程对象而创建的stub将会被传递,而不是传递远程对象它自己的拷贝。远程实现对象,比如ComputeEngine的实例不会离开创建它的JVM.因此,当一个客户端程序在服务器端远程对象registry执行查找的时候,将会返回stub的拷贝。像这种情况下的远程是通过引用而不是通过值的方式来传递的。
•For security reasons, an application can only bind, unbind, or rebind remote object references with a registry running on the same host. This restriction prevents a remote client from removing or overwriting any of the entries in a server's registry. A lookup, however, can be requested from any host, local or remote.
Once the server has registered with the local RMI registry, it prints a message indicating that it is ready to start handling calls. Then, the main method completes. It is not necessary to have a thread wait to keep the server alive. As long as there is a reference to the ComputeEngine object in another Java virtual machine, local or remote, the ComputeEngine object will not be shut down or garbage collected. Because the program binds a reference to the ComputeEngine in the registry, it is reachable from a remote client, the registry itself. The RMI system keeps the ComputeEngine's process running. The ComputeEngine is available to accept calls and won't be reclaimed until its binding is removed from the registry and no remote clients hold a remote reference to the ComputeEngine object.
出于安全考虑,一个应用程序只能在同一个主机中运行的registr中绑定,解除绑定或重新绑定远程对象的引用。这种限制可以阻止远程客户端删除或重写服务器registry的任何一个实体。然而,对于查找来说,却可以被任何主机(本地的或远程的)请求。当服务器注册到本地RMI registry时,它就会打印出消息用于表明它已经准备好可以开始处理调用。然后,
main方法就完成了。没有必要使用一个线程来等待服务器激活。只要有一个在另外的JVM中的puteEngine的引用,不管是本地的,还是远程的,ComputeEngine对象将不会关闭或进行垃圾回收。因为程序将ComputeEngine的引用绑定到了registry中,从远程客户端来说它是可到达的。RMI系统会保持ComputeEngine一直处于运行状态。ComputeEngine会一直接受调用并不会被回收,除非它的绑定从registry中被删除了且无远程客户端不再持有ComputeEngine对象的远程引用。
The final piece of code in the ComputeEngine.main method handles any exception that might arise. The only checked exception type that could be thrown in the code is RemoteException, either by the UnicastRemoteObject.exportObject invocation or by the registry rebind invocation. In either case, the program cannot do much more than exit after printing an error message. In some distributed applications, recovering from the failure to make a remote invocation is possible. For example, the application could attempt to retry the operation or choose another server to continue the operation.
ComputeEngine.main方法的最后一块代码用于处理任何可能出现的异常。唯一的可能在代码中抛出的一个受查异常类型是RemoteException,要么是通过UnicastRemoteObject.exportObject方法调用所引发的,要么是通过registry的rebind方法调用引发的。无论哪种情况,程序除了在打印错误信息后退出外,不能执行更多的操作。在一些分布式应用程序中,容错恢复可以使得一个远程调用变得可能。如,应用程序可以试图重新尝试失败的操作或者是选者另一个服务器来继续执行操作。
This section discusses the task of implementing a class for the compute engine. In general, a class that implements a remote interface should at least do the following:
实现一个远程接口
这个章节讨论计算引擎的实现类。一般来说,实现一个远程接口的类至少应该遵循以下规则:
•Declare the remote interfaces being implemented
•Define the constructor for each remote object
•Provide an implementation for each remote method in the remote interfaces
•定义一个用于实现的远程接口
•为每个远程对象定义构造函数
•实现远程接口中定义的每一个远程方法
An RMI server program needs to create the initial remote objects and export them to the RMI runtime, which makes them available to receive incoming remote invocations. This setup procedure can be either encapsulated in a method of the remote object implementation class itself or included in another class entirely. The setup procedure should do the following:
一个RMI服务器端程序需要创建最初的远程对象,并把这些远程对象导出到RMI的运行时环境中,这些运行时环境使得它们可以接收到远程调用.这个设置过程可以封装在远程对象的方法中,也可以完全包含在另一个类里。此设置过程如下:
•Create and install a security manager
•Create and export one or more remote objects
•Register at least one remote object with the RMI registry (or with
another naming service, such as a service accessible through the Java Naming and Directory Interface) for bootstrapping purposes
The complete implementation of the compute engine follows. The engine.ComputeEngine class implements the remote interface Compute and also includes the main method for setting up the compute engine.
•创建和安装一个安全管理器
•创建和导出一个或多个远程对象
•至少在RMI registry(或另外的命名与目录接口)中注册一个远程对象。engine.ComputeEngine类实现了Compute远程接口,同时也在main方法中设置了计算引擎。
Here is the source code for the ComputeEngine class:
以下是ComputeEngine类的源代码:
package engine; import java.rmi.RemoteException; import java.rmi.registry.LocateRegistry; import java.rmi.registry.Registry; import java.rmi.server.UnicastRemoteObject; import compute.Compute; import compute.Task; public class ComputeEngine implements Compute { public ComputeEngine() { super(); } public <T> T executeTask(Task<T> t) { return t.execute(); } public static void main(String[] args) { if (System.getSecurityManager() == null) { System.setSecurityManager(new SecurityManager()); } try { String name = "Compute"; Compute engine = new ComputeEngine(); Compute stub = (Compute) UnicastRemoteObject.exportObject(engine, 0); Registry registry = LocateRegistry.getRegistry(); registry.rebind(name, stub); System.out.println("ComputeEngine bound"); } catch (Exception e) { System.err.println("ComputeEngine exception:"); e.printStackTrace(); } } }
The following sections discuss each component of the compute engine implementation.
接下来的部分将讨论计算引擎实现类的各个组成部分。
Declaring the Remote Interfaces Being Implemented
The implementation class for the compute engine is declared as follows:
实现计算引擎的实现声明如下:
public class ComputeEngine implements Compute
This declaration states that the class implements the Compute remote interface and therefore can be used for a remote object.
这个声明表明实现远程接口Compute的类可以用作远程对象。
The ComputeEngine class defines a remote object implementation class that implements a single remote interface and no other interfaces. The ComputeEngine class also contains two executable program elements that can only be invoked locally. The first of these elements is a constructor for ComputeEngine instances. The second of these elements is a main method that is used to create a ComputeEngine instance and make it available to clients.
ComputeEngine类只定义了实现了一个远程接口的远程对象。同时它也包含两个只能用于本地调用的方法。第一个是用于构建ComputeEngine的构造函数。第二个是main方法,用于创建ComputeEngine实例并使其对于客户端可用。
Defining the Constructor for the Remote Object
The ComputeEngine class has a single constructor that takes no arguments. The code for the constructor is as follows:
定义远程对象的构造函数,ComputeEngine类只有一个无参的构造函数,其声明如下:
public ComputeEngine() { super(); }
This constructor just invokes the superclass constructor, which is the no-argument constructor of the Object class. Although the superclass constructor gets invoked even if omitted from the ComputeEngine constructor, it is included for clarity.
这个构造函数调用了超类的无参构造函数。尽管超类的构造函数即便在ComputeEngine构造函数中省略的情况下也能得到调用,但还是应该明确调用。
Providing Implementations for Each Remote Method
The class for a remote object provides implementations for each remote method specified in the remote interfaces. The Compute interface contains a single remote method, executeTask, which is implemented as follows:
为每个远程方法提供实现
远程对象类实现了远程接口中指定的每一个远程方法。Compute接口仅含有一个远程方法executeTask,其具体实现如下:
public <T> T executeTask(Task<T> t) { return t.execute(); }
This method implements the protocol between the ComputeEngine remote object and its clients. Each client provides the ComputeEngine with a Task object that has a particular implementation of the Task interface's execute method. The ComputeEngine executes each client's task and returns the result of the task's execute method directly to the client.
这个方法实现了ComputeEngine远程对象和它的客户端之间的协议。每个客户端提供了Task接口的execute方法的具体实现。ComputeEngine执行每个客户端任务并将其结果直接返回给客户端。
Passing Objects in RMI
Arguments to or return values from remote methods can be of almost any type, including local objects, remote objects, and primitive data types. More precisely, any entity of any type can be passed to or from a remote method as long as the entity is an instance of a type that is a primitive data type, a remote object, or a serializable object, which means that it implements the interface java.io.Serializable.
在RMI中传递对象
远程方法的参数或返回值几乎可以是任何数据类型,包括本地对象,远程对象以及原始类型。
更准确地说,任何类型的任何实体都可以作为远程方法的参数或返回值,只要这个实体是原始数据类型,远程对象或实现了java.io.Serializable接口的序列化对象的实例.
Some object types do not meet any of these criteria and thus cannot be passed to or returned from a remote method. Most of these objects, such as threads or file descriptors, encapsulate information that makes sense only within a single address space. Many of the core classes, including the classes in the packages java.lang and java.util, implement the Serializable interface.
如果某个对象不满足上述条件中的任何一个,就不能作为远程方法的参数或返回值。比如线程或文件描述,就不能作为远程方法的参数和返回值。许多核心类,包括java.lang 和java.util包中的类都实现了Serializable接口。
The rules governing how arguments and return values are passed are as follows:
参数和返回值是通过以下规则确定的:
•Remote objects are essentially passed by reference. A remote object reference is a stub, which is a client-side proxy that implements the complete set of remote interfaces that the remote object implements.
•Local objects are passed by copy, using object serialization. By default, all fields are copied except fields that are marked static or transient. Default serialization behavior can be overridden on a class-by-class basis.
Passing a remote object by reference means that any changes made to the state of the object by remote method invocations are reflected in the original remote object. When a remote object is passed, only those interfaces that are remote interfaces are available to the receiver. Any methods defined in the implementation class or defined in non-remote interfaces implemented by the class are not available to that receiver.
•远程对象本质是通过引用来传递的。一个远程对象的引用是一个stub(存根),stub是一个完全实现了远程接口的客户端代理。
•本地对象是通过拷贝来传递的,使用的是对象序列化。默认情况下,除了标记为static,transient的字段都会被拷贝。默认的序列化行可以通过基于class-by-class的方式进行覆盖。
通过引用来传递远程对象,意味着被远程方法调用的对象状态的任何修改都会反映到原来的远程对象上。当远程对象被传递时,只有那些远程接口对于接收者(客户端)是有效的。任何定义在实现类的方法或定义在实现非远程接口中的方法对于客户端来说都是无效的。
For example, if you were to pass a reference to an instance of the ComputeEngine class, the receiver would have access only to the compute engine's executeTask method. That receiver would not see the ComputeEngine constructor, its main method, or its implementation of any methods of java.lang.Object.
比如,如果我们传递一个引用给ComputeEngine类的实例,那么接收者只能访问计算引擎的executeTask方法。那个接收者不能看到ComputeEngine的构造方法,main方法或者java.lang.Object任何方法的实现。
In the parameters and return values of remote method invocations, objects that are not remote objects are passed by value. Thus, a copy of the object is created in the receiving Java virtual machine. Any changes to the object's state by the receiver are reflected only in the receiver's copy, not in the sender's original instance. Any changes to the object's state by the sender are reflected only in the sender's original instance, not in the receiver's copy.
在远程方法调用的参数和返回值中,非远程对象的传递是通过值的方式来进行的。因此,对象的拷贝将会在接收的JVM被创建。被接收者修改的任何对象状态的改变只能反映在接收者的拷贝中,而不反映在发送者的原始实例中。被发送者修改的任何对象状态的改变只能反映在发送者的原始实例中,而不反映在接收者的拷贝中。
Implementing the Server's main Method
The most complex method of the ComputeEngine implementation is the main method. The main method is used to start the ComputeEngine and therefore needs to do the necessary initialization and housekeeping to prepare the server to accept calls from clients. This method is not a remote method, which means that it cannot be invoked from a different Java virtual machine. Because the main method is declared static, the method is not associated with an object at all but rather with the class ComputeEngine.
实现服务器的main方法
ComputeEngine实现最复杂的部分便是main方法。此方法用于启动ComputeEngine,因此需要作必要的初始化和准备工作以便接受客户端的调用。此方法不是远程方法,这意味着它不能被不同的JVM所调用。因为main方法被声明为static的,因此它与ComputeEngine类相关的,而不是与ComputeEngine的实例相关的。
Creating and Installing a Security Manager
The main method's first task is to create and install a security manager, which protects access to system resources from untrusted downloaded code running within the Java virtual machine. A security manager determines whether downloaded code has access to the local file system or can perform any other privileged operations.
创建和初始化安全管理器
main方法的第一个任务是创建和安装一个安全管理器,其目的是防止运行在JVM中的下载的不可信任的代码访问系统资源。安全管理器将决定下载的代码能否访问本地文件系统或执行其他有特权的操作。
If an RMI program does not install a security manager, RMI will not download classes (other than from the local class path) for objects received as arguments or return values of remote method invocations. This restriction ensures that the operations performed by downloaded code are subject to a security policy.
如果一个RMI程序没有安装安全管理器,RMI将不会为了远程方法调用的参数和返回值下载字节码(除了那些来自本地类路径的类外)。这种限制保证下载代码执行的操作符合安全策略。
Here's the code that creates and installs a security manager:
以下是创建和安装安全管理器的代码:
if (System.getSecurityManager() == null) { System.setSecurityManager(new SecurityManager()); }
Making the Remote Object Available to Clients
Next, the main method creates an instance of ComputeEngine and exports it to the RMI runtime with the following statements:
使远程对象对客户端可用
下一步,main方法创建了一个ComputeEngine的实例,并使用以下语句将它导出到RMI运行时环境:
Compute engine = new ComputeEngine(); Compute stub = (Compute) UnicastRemoteObject.exportObject(engine, 0);
The static UnicastRemoteObject.exportObject method exports the supplied remote object so that it can receive invocations of its remote methods from remote clients. The second argument, an int, specifies which TCP port to use to listen for incoming remote invocation requests for the object. It is common to use the value zero, which specifies the use of an anonymous port. The actual port will then be chosen at runtime by RMI or the underlying operating system. However, a non-zero value can also be used to specify a specific port to use for listening. Once the exportObject invocation has returned successfully, the ComputeEngine remote object is ready to process incoming remote invocations.
UnicastRemoteObject.exportObject静态方法用于导出远程对象,以便能被远程客户端的远程方法调用。第二个整形参数,用于指定监听远程调用的TCP端口.通常情况下,它使用0,表示使用一个匿名端口,实际端口将通过RMI在运行时指定或由底层操作系统指定。而对于非0的端口,将被用作监听的特定端口。一旦exportObject调用成功返回,ComputeEngine远程对象就开始准备好处理到来的远程调用。
The exportObject method returns a stub for the exported remote object. Note that the type of the variable stub must be Compute, not ComputeEngine, because the stub for a remote object only implements the remote interfaces that the exported remote object implements.
exportObject方法返回一个已导出的远程对象的存根。注意,stub变量的类型必须是Comute接口,而不是ComuteEngine,因为远程对象的stub只实现了导出的远程对象实现的远程接口。
The exportObject method declares that it can throw a RemoteException, which is a checked exception type. The main method handles this exception with its try/catch block. If the exception were not handled in this way, RemoteException would have to be declared in the throws clause of the main method. An attempt to export a remote object can throw a RemoteException if the necessary communication resources are not available, such as if the requested port is bound for some other purpose.
exportObject方法能抛出一个RemoteException,它是一个受查异常。main方法通过try/catch语句块来处理这个异常。如果异常不以这种方式处理,main方法就应该将其抛出。地导出一个远程对象的时候,如果因为必要的通信资源不可用,那么将会抛出RemoteException。比如请求的端口由于其他目的而被占用。
Before a client can invoke a method on a remote object, it must first obtain a reference to the remote object. Obtaining a reference can be done in the same way that any other object reference is obtained in a program, such as by getting the reference as part of the return value of a method or as part of a data structure that contains such a reference.
在一个客户端能调用远程对象的方法前,它必须首先获得远程对象的引用。
The system provides a particular type of remote object, the RMI registry, for finding references to other remote objects. The RMI registry is a simple remote object naming service that enables clients to obtain a reference to a remote object by name. The registry is typically only used to locate the first remote object that an RMI client needs to use. That first remote object might then provide support for finding other objects.
系统提供了远程对象的特别类型,RMI registry,用于查找其他远程的引用。RMI registry是一个简单的远程对象命名服务,它使得客户端能够通过名字获取到远程对象的引用。registry典型地用于定位RMI客户端要用到的第一个远程对象。第一个远程对象然后为查找其他对象提供支持。
The java.rmi.registry.Registry remote interface is the API for binding (or registering) and looking up remote objects in the registry. The java.rmi.registry.LocateRegistry class provides static methods for synthesizing a remote reference to a registry at a particular network address (host and port). These methods create the remote reference object containing the specified network address without performing any remote communication. LocateRegistry also provides static methods for creating a new registry in the current Java virtual machine, although this example does not use those methods. Once a remote object is registered with an RMI registry on the local host, clients on any host can look up the remote object by name, obtain its reference, and then invoke remote methods on the object. The registry can be shared by all servers running on a host, or an individual server process can create and use its own registry.
java.rmi.registry.Registry远程接口是用于在注册机中注册和查找远程对象的应用程序编程接口。java.rmi.registry.LocateRegistry类提供了静态方法来从实际的网络地址(主机和端口)获取远程引用。这些方法根据指定的网络地址,不执行任何远程通信来创建远程引用对象。同时LocateRegistry也提供静态方法在当前JVM中创建一个新的registry,尽管这个示例中没有用到这些方法。一旦一个远程对象注册到本地RMI registry中,在任何主机上的客户端都能通过名字查找到远程对象,获取它的引用,然后调用对象上的方法。registry能够被运行在一台主机的所有服务器所共享,也可以用一台单独的服务来创建和使用它自己的registry.
The ComputeEngine class creates a name for the object with the following statement:
ComputeEngine使用下面的语句来为对象创建一个名字:
String name = "Compute";
The code then adds the name to the RMI registry running on the server. This step is done later with the following statements:
然后代码将此名字加到正在服务端运行的RMI registry中。这个步骤是通过以下语句完成的。
Registry registry = LocateRegistry.getRegistry(); registry.rebind(name, stub);
This rebind invocation makes a remote call to the RMI registry on the local host. Like any remote call, this call can result in a RemoteException being thrown, which is handled by the catch block at the end of the main method.
Note the following about the Registry.rebind invocation:
•The no-argument overload of LocateRegistry.getRegistry synthesizes a reference to a registry on the local host and on the default registry port, 1099. You must use an overload that has an int parameter if the registry is created on a port other than 1099.
无参的重载方法LocateRegistry.getRegistry将会在本地主机和缺省端口1099中得到一个registry的引用。如果创建registry的端口不是1099,你可以使用重载的带int参数的方法。
•When a remote invocation on the registry is made, a stub for the remote object is passed instead of a copy of the remote object itself. Remote implementation objects, such as instances of ComputeEngine, never leave the Java virtual machine in which they were created. Thus, when a client performs a lookup in a server's remote object registry, a copy of the stub is returned. Remote objects in such cases are thus effectively passed by (remote) reference rather than by value.
当一个远程调用在registry中发生的时候,为远程对象而创建的stub将会被传递,而不是传递远程对象它自己的拷贝。远程实现对象,比如ComputeEngine的实例不会离开创建它的JVM.因此,当一个客户端程序在服务器端远程对象registry执行查找的时候,将会返回stub的拷贝。像这种情况下的远程是通过引用而不是通过值的方式来传递的。
•For security reasons, an application can only bind, unbind, or rebind remote object references with a registry running on the same host. This restriction prevents a remote client from removing or overwriting any of the entries in a server's registry. A lookup, however, can be requested from any host, local or remote.
Once the server has registered with the local RMI registry, it prints a message indicating that it is ready to start handling calls. Then, the main method completes. It is not necessary to have a thread wait to keep the server alive. As long as there is a reference to the ComputeEngine object in another Java virtual machine, local or remote, the ComputeEngine object will not be shut down or garbage collected. Because the program binds a reference to the ComputeEngine in the registry, it is reachable from a remote client, the registry itself. The RMI system keeps the ComputeEngine's process running. The ComputeEngine is available to accept calls and won't be reclaimed until its binding is removed from the registry and no remote clients hold a remote reference to the ComputeEngine object.
出于安全考虑,一个应用程序只能在同一个主机中运行的registr中绑定,解除绑定或重新绑定远程对象的引用。这种限制可以阻止远程客户端删除或重写服务器registry的任何一个实体。然而,对于查找来说,却可以被任何主机(本地的或远程的)请求。当服务器注册到本地RMI registry时,它就会打印出消息用于表明它已经准备好可以开始处理调用。然后,
main方法就完成了。没有必要使用一个线程来等待服务器激活。只要有一个在另外的JVM中的puteEngine的引用,不管是本地的,还是远程的,ComputeEngine对象将不会关闭或进行垃圾回收。因为程序将ComputeEngine的引用绑定到了registry中,从远程客户端来说它是可到达的。RMI系统会保持ComputeEngine一直处于运行状态。ComputeEngine会一直接受调用并不会被回收,除非它的绑定从registry中被删除了且无远程客户端不再持有ComputeEngine对象的远程引用。
The final piece of code in the ComputeEngine.main method handles any exception that might arise. The only checked exception type that could be thrown in the code is RemoteException, either by the UnicastRemoteObject.exportObject invocation or by the registry rebind invocation. In either case, the program cannot do much more than exit after printing an error message. In some distributed applications, recovering from the failure to make a remote invocation is possible. For example, the application could attempt to retry the operation or choose another server to continue the operation.
ComputeEngine.main方法的最后一块代码用于处理任何可能出现的异常。唯一的可能在代码中抛出的一个受查异常类型是RemoteException,要么是通过UnicastRemoteObject.exportObject方法调用所引发的,要么是通过registry的rebind方法调用引发的。无论哪种情况,程序除了在打印错误信息后退出外,不能执行更多的操作。在一些分布式应用程序中,容错恢复可以使得一个远程调用变得可能。如,应用程序可以试图重新尝试失败的操作或者是选者另一个服务器来继续执行操作。
发表评论
-
RMI中的安全策略
2012-07-13 15:58 3564以下翻译来自Java RMI的Ch ... -
RMI动态类加载
2012-07-13 15:14 1508以下翻译自Java RMI的Chapter 19.Dynami ... -
RMI运行时说明
2012-07-06 12:25 2958RMI运行时环境在客户端和服务端都扮演了重要的角色.在这种架构 ... -
RMI中的属性说明
2012-07-03 18:06 1371服务端属性 下面的表 ... -
O'reilly<<Java RMI>> 第18章:使用定制Socket (翻译)
2012-06-30 16:15 1531以下翻译来自:o'reilly ... -
RMI规范--第一章
2012-06-29 10:52 920原文网址: http://docs.or ... -
RMI规范--第十章
2012-06-29 10:50 758RMI 通信协议 10.1 概述 ... -
RMI规范--第九章
2012-06-29 10:29 843本章中的接口和类用于 ... -
RMI规范--第八章
2012-06-29 10:13 611本章包含 rmic stub 编译 ... -
RMI规范--第七章
2012-06-29 09:38 864远程对象激活 主题: 概述 激活协议 “可激活 ... -
RMI规范--第六章
2012-06-28 00:17 901注册服务程序接口 RMI 系统使用 java.rmi.re ... -
RMI规范--第五章
2012-06-28 00:16 905服务器接口 java.rmi.server 包包含通常用于 ... -
RMI规范--第四章
2012-06-28 00:15 839客户机接口 程序员在编写使用远程对象的 applet 或应 ... -
RMI规范--第三章
2012-06-28 00:14 800主题: Stub 与 skeleton ... -
RMI规范--第二章
2012-06-28 00:13 978Java 分布式对象模型 2.1 分布式对象应用程序 ... -
J2SE1.6 RMI官方指南翻译四
2012-06-27 18:20 1016Compiling and Running the Examp ... -
J2SE1.6 RMI官方指南翻译三
2012-06-27 18:16 826Creating a Client Program The c ... -
J2SE1.6 RMI官方指南翻译一
2012-06-27 16:37 881最近在学习分布式 ... -
RMI 开发步骤
2012-06-25 18:36 1426开发RMI步骤: 1.编写服务接口,此接口须直接或间接继承至R ... -
JDK1.6 rmic命令使用
2012-06-25 18:24 1460rmic称为rmi编译命令,用于生成rmi远程实现类的stub ...
相关推荐
j2se1.6官方中文API 官方网站下载,一共三部分
J2SE 1.6 JDK API 中文版》中文chm版 计算机电子书下载,很不错的资料共18个文件,《J2SE 1.6 JDK API 中文版》电子书,是jdk api的,非常值得一看,欢迎下载《J2SE 1.6 JDK API》计算机电子书。希望对大家有所帮助
J2SE1.6.chm 官方帮助文档,chm格式,使用更加方便
J2SE 1.6 JDK API 中文版》中文chm版 计算机电子书下载,很不错的资料共18个文件,《J2SE 1.6 JDK API 中文版》电子书,是jdk api的,非常值得一看,欢迎下载《J2SE 1.6 JDK API》计算机电子书。希望对大家有所帮助
Java 2 Standard Edition (J2SE) 是 Java 平台的核心部分,主要用于桌面应用程序的开发和执行。J2SE 1.6 版本是 Sun Microsystems(后被Oracle收购)在2006年发布的,它包含了Java语言的关键特性和库,为开发者提供...
Java 2 Platform, Standard Edition (J2SE) 1.6 和 Java 2 Platform, Enterprise Edition (J2EE) 1.6 是Java开发的重要版本,它们提供了丰富的API和技术支持,为开发桌面应用和企业级应用奠定了基础。下面将详细讨论...