RMI System Overview
          

        注:主要內(nèi)容參考官方文檔。同時(shí)已經(jīng)有人把翻譯過(guò)Sun上RMI的lesson,如果想學(xué)習(xí)技術(shù)實(shí)例,可以查看,參考資源給出了鏈接。

3.1 Stubs and Skeletons

RMI uses a standard mechanism (employed in RPC systems) for communicating with remote objects: stubs and
skeletons. A stub for a remote object acts as a client's local representative or proxy for the remote object
. The caller invokes a method on the local stub which is responsible for carrying out the method call on the
 remote object. In RMI, a stub for a remote object implements the same set of remote interfaces that a
remote object implements.

RMI為遠(yuǎn)程對(duì)象的通訊使用一個(gè)標(biāo)準(zhǔn)的機(jī)制(在RPC系統(tǒng)中使用):stubs和skeletons.一個(gè)遠(yuǎn)程對(duì)象的stub為遠(yuǎn)程對(duì)象作為一個(gè)客戶端本地的代表或者代理.當(dāng)調(diào)用者在本地的stub中調(diào)用一個(gè)方法,stub負(fù)責(zé)實(shí)現(xiàn)調(diào)用遠(yuǎn)程對(duì)象的方法.在RMI中,一個(gè)遠(yuǎn)程對(duì)象的stub實(shí)現(xiàn)了所有遠(yuǎn)程對(duì)象實(shí)現(xiàn)的接口.


When a stub's method is invoked, it does the following:
•    initiates a connection with the remote JVM containing the remote object,
•    marshals (writes and transmits) the parameters to the remote JVM,
•    waits for the result of the method invocation,
•    unmarshals (reads) the return value or exception returned, and
•    returns the value to the caller.


當(dāng)一個(gè)stub的方法被調(diào)用時(shí),它遵循下面步驟:
    與包含遠(yuǎn)程對(duì)象的JVM之間創(chuàng)建一個(gè)連接.
    傳遞(寫(xiě)入和發(fā)送)參數(shù)到遠(yuǎn)程的JVM.
    等待方法調(diào)用的結(jié)果
    讀取返回值或者異常.
    返回結(jié)果給調(diào)用者.


The stub hides the serialization of parameters and the network-level communication in order to present a
simple invocation mechanism to the caller.
In the remote JVM, each remote object may have a corresponding skeleton (in Java 2 platform-only
environments, skeletons are not required). The skeleton is responsible for dispatching the call to the
actual remote object implementation. When a skeleton receives an incoming method invocation it does the
following:
•    unmarshals (reads) the parameters for the remote method,
•    invokes the method on the actual remote object implementation, and
•    marshals (writes and transmits) the result (return value or exception) to the caller.

Stub隱藏了參數(shù)的序列化和網(wǎng)絡(luò)級(jí)別的通訊,調(diào)用者看到的是個(gè)簡(jiǎn)單的調(diào)用機(jī)制.
在遠(yuǎn)程的JVM中,每個(gè)遠(yuǎn)程對(duì)象可能有一個(gè)相同的skeleton(僅僅在java2平臺(tái)中,skeletons不是必要的).skeleton的職責(zé)是分發(fā)調(diào)用到實(shí)際遠(yuǎn)程對(duì)象的實(shí)現(xiàn).一個(gè)skeleton接收到一個(gè)方法的調(diào)用,它執(zhí)行下面步驟:

   讀取這個(gè)為調(diào)用遠(yuǎn)程方法傳遞過(guò)來(lái)的參數(shù).
   調(diào)用實(shí)際的遠(yuǎn)程對(duì)象實(shí)現(xiàn)的方法.
•   返回結(jié)果給調(diào)用者(值或者異常)


In the Java 2 SDK, Standard Edition, v1.2 an additional stub protocol was introduced that eliminates the
need for skeletons in Java 2 platform-only environments. Instead, generic code is used to carry out the
duties performed by skeletons in JDK1.1. Stubs and skeletons are generated by the rmic compiler.

在Java2 SE v1.2中附加了一個(gè)stub協(xié)議介紹:在java2平臺(tái)環(huán)境中,不再需要skeletons. 在JDK1.1中還是通過(guò)skeletons來(lái)操作,Stubs和skeletons通過(guò)rmic編譯器生成.



3.2 Thread Usage in Remote Method Invocations

A method dispatched by the RMI runtime to a remote object implementation may or may not execute in a
separate thread. The RMI runtime makes no guarantees with respect to mapping remote object invocations to
threads. Since remote method invocation on the same remote object may execute concurrently, a remote object implementation needs to make sure its implementation is thread-safe.


一個(gè)方法由RMI運(yùn)行期分發(fā)給一個(gè)遠(yuǎn)程對(duì)象的實(shí)現(xiàn),有可能啟用的不是單獨(dú)的線程.RMI運(yùn)行期不保準(zhǔn)遠(yuǎn)程方法的調(diào)用與線程聯(lián)系起來(lái),一旦遠(yuǎn)程方法調(diào)用同一個(gè)對(duì)象可能會(huì)并發(fā)執(zhí)行,所以要確保遠(yuǎn)程對(duì)象的實(shí)現(xiàn)是線程安全的.



3.3 Garbage Collection of Remote Objects

In a distributed system, just as in the local system, it is desirable to automatically delete those remote
objects that are no longer referenced by any client. This frees the programmer from needing to keep track
of the remote objects' clients so that it can terminate appropriately. RMI uses a reference-counting garbage
 collection algorithm similar to Modula-3's Network Objects. (See "Network Objects" by Birrell, Nelson, and
 Owicki, Digital Equipment Corporation Systems Research Center Technical Report 115, 1994.)

在分布式系統(tǒng)中和本地系統(tǒng)一樣,自動(dòng)刪除不再被客戶端使用的遠(yuǎn)程對(duì)象是合符要求的,要釋放這些程序必須追蹤遠(yuǎn)程對(duì)象的客戶端,以確保什么時(shí)候釋放是合適的.RMI使用一個(gè)reference-counting垃圾回收的計(jì)算規(guī)則.和Modula-3's Network Objects.相似. (See "Network Objects" by Birrell, Nelson, and Owicki, Digital Equipment Corporation Systems Research Center Technical Report 115, 1994.)


To accomplish reference-counting garbage collection, the RMI runtime keeps track of all live references
within each Java virtual machine. When a live reference enters a Java virtual machine, its reference count
is incremented. The first reference to an object sends a "referenced" message to the server for the object.
As live references are found to be unreferenced in the local virtual machine, the count is decremented. When
 the last reference has been discarded, an unreferenced message is sent to the server. Many subtleties exist
 in the protocol; most of these are related to maintaining the ordering of referenced and unreferenced
messages in order to ensure that the object is not prematurely collected.

為了完成reference-counting垃圾回收,RMI運(yùn)行期跟蹤JVM中所有活動(dòng)的引用.一旦有一個(gè)活動(dòng)的引用進(jìn)入JVM,它的引用計(jì)算值就自動(dòng)遞增,這個(gè)對(duì)象的第一個(gè)引用發(fā)送一個(gè)"referenced"消息到服務(wù)器端,當(dāng)活動(dòng)引用發(fā)現(xiàn)沒(méi)有與本地的JVM關(guān)聯(lián),這個(gè)計(jì)算值就自動(dòng)遞減.當(dāng)最后一個(gè)引用被廢棄,一條’未引用’的消息就會(huì)發(fā)送到服務(wù)器端.這個(gè)協(xié)議存在許多細(xì)微之處,大部分這些關(guān)聯(lián)是為了維持引用和接觸引用的順序,以確保對(duì)象不被過(guò)早的回收.


When a remote object is not referenced by any client, the RMI runtime refers to it using a weak reference.
The weak reference allows the Java virtual machine's garbage collector to discard the object if no other
local references to the object exist. The distributed garbage collection algorithm interacts with the local Java virtual machine's garbage collector in the usual ways by holding normal or weak references to objects.

當(dāng)一個(gè)遠(yuǎn)程對(duì)象不被任何客戶端引用,RMI運(yùn)行期使用一個(gè)弱引用關(guān)聯(lián),如果這個(gè)對(duì)象沒(méi)有其它本地引用關(guān)聯(lián),這個(gè)弱引用允許JVM的垃圾回收器回收.通過(guò)持有對(duì)象的普通引用或者弱移用,分布式的垃圾回收規(guī)則和本地的垃圾回收器使用正常的方式相互影響.


As long as a local reference to a remote object exists, it cannot be garbage-collected and it can be passed in remote calls or returned to clients. Passing a remote object adds the identifier for the virtual machine to which it was passed to the referenced set. A remote object needing unreferenced notification must
implement the java.rmi.server.Unreferenced interface. When those references no longer exist, the
unreferenced method will be invoked. unreferenced is called when the set of references is found to be empty so it might be called more than once. Remote objects are only collected when no more references, either
local or remote, still exist.

只要一個(gè)與遠(yuǎn)程對(duì)象關(guān)聯(lián)的本地引用存在,它就不能被回收,并且能在遠(yuǎn)程調(diào)用或者返回客戶端時(shí)傳遞.傳遞一個(gè)遠(yuǎn)程對(duì)象為JVM增加一個(gè)標(biāo)識(shí),且是以引用的方式傳遞的.遠(yuǎn)程對(duì)象需要未引用的通知必須實(shí)現(xiàn)java.rmi.server.Unreferenced接口,當(dāng)這些引用不在存在時(shí),unreferenced方法就會(huì)被調(diào)用,當(dāng)引用的集合發(fā)現(xiàn)是空的時(shí)候,unreferenced就會(huì)被調(diào)用,所以它可能不止一次的被調(diào)用.遠(yuǎn)程對(duì)象只有當(dāng)沒(méi)有任何引用的時(shí)候才能被回收,不管是本地或者遠(yuǎn)程的.



Note that if a network partition exists between a client and a remote server object, it is possible that
premature collection of the remote object will occur (since the transport might believe that the client
crashed). Because of the possibility of premature collection, remote references cannot guarantee referential
 integrity; in other words, it is always possible that a remote reference may in fact not refer to an
existing object. An attempt to use such a reference will generate a RemoteException which must be handled by
 the application.

注意一旦客戶端和服務(wù)器端的網(wǎng)絡(luò)斷開(kāi),預(yù)期的遠(yuǎn)程對(duì)象的回收可能會(huì)發(fā)生.所以不能確保遠(yuǎn)程引用都是正常的,換句話說(shuō),嘗試使用這樣一個(gè)引用將會(huì)拋出一個(gè)RemoteException


3.4 Dynamic Class Loading

RMI allows parameters, return values and exceptions passed in RMI calls to be any object that is serializable
. RMI uses the object serialization mechanism to transmit data from one virtual machine to another and also annotates the call stream with the appropriate location information so that the class definition files can
be loaded at the receiver.

RMI調(diào)用時(shí)允許參數(shù),返回值和異常傳遞給序列化的任何對(duì)象.RMI使用對(duì)象序列化機(jī)制在不同JVM之間傳輸數(shù)據(jù),并且用合適的本地信息給調(diào)用流做注解,所以class定義文件可以被接收者加載.

When parameters and return values for a remote method invocation are unmarshalled to become live objects in the receiving JVM, class definitions are required for all of the types of objects in the stream. The unmarshal
ling process first attempts to resolve classes by name in its local class loading context (the context class
 loader of the current thread). RMI also provides a facility for dynamically loading the class definitions
for the actual types of objects passed as parameters and return values for remote method invocations from
network locations specified by the transmitting endpoint. This includes the dynamic downloading of remote
stub classes corresponding to particular remote object implementation classes (and used to contain remote
references) as well as any other type that is passed by value in RMI calls, such as the subclass of a
declared parameter type, that is not already available in the class loading context of the unmarshalling side
.

當(dāng)遠(yuǎn)程對(duì)象調(diào)用的參數(shù)和返回值在接收的JVM中被unmarshalled為對(duì)象時(shí),在流中所有對(duì)象的類型必須要求有class注解. unmarshalling過(guò)程首先嘗試使用當(dāng)前線程的class加載器通過(guò)名字加載classes.RMI也提供一種動(dòng)態(tài)加載class定義.在從網(wǎng)絡(luò)中一個(gè)位置,特別的是傳輸末端的遠(yuǎn)程方法調(diào)用傳輸參數(shù)和返回值對(duì)象的實(shí)際類型.包括動(dòng)態(tài)下載遠(yuǎn)程stub classes,其與遠(yuǎn)程對(duì)象實(shí)現(xiàn)classes一致(包含遠(yuǎn)程引用),而且包括在RMI調(diào)用中其它任何傳值類型.比如聲明參數(shù)類型的子類,在unmarshalling的這邊使用類加載context加載沒(méi)什么用處。

To support dynamic class loading, the RMI runtime uses special subclasses of java.io.ObjectOutputStream and java.io.ObjectInputStream for the marshal streams that it uses for marshalling and unmarshalling RMI parameters
 and return values. These subclasses respectively override the annotateClass method of ObjectOutputStream
and the resolveClass method of ObjectInputStream to communicate information about where to locate class files
 containing the definitions for classes corresponding to the class descriptors in the stream.


為支持動(dòng)態(tài)Class加載,RMI運(yùn)行期針對(duì)marshal流使用特別的java.io.ObjectOutputStream和 java.io.ObjectInputStream子集。Marshal流是用來(lái)marshalling和unmarshalling RMI參數(shù)和返回值。這個(gè)子集分別覆蓋了ObjectOutputStream的annotateClass的方法和ObjectInputStream的resolveClass方法傳達(dá)在流中哪里可以找到包含classes定義以及相應(yīng)的class修飾符的class文件信息。


For every class descriptor written to an RMI marshal stream, the annotateClass method adds to the stream the
 result of calling java.rmi.server.RMIClassLoader.getClassAnnotation for the class object, which may be null
 or may be a String object representing the codebase URL path (a space-separated list of URLs) from which the
 remote endpoint should download the class definition file for the given class.

寫(xiě)入RMI marshal流中的每一個(gè)修飾符,annotateClass方法被加入到流中,對(duì)象調(diào)用ava.rmi.server.RMIClassLoader.getClassAnnotation的結(jié)果可能是null值,也可以能使表示一個(gè)codebase URL路徑的String對(duì)象。遠(yuǎn)程末端將為制定的class從這個(gè)URL中加載class定義。


For every class descriptor read from an RMI marshal stream, the resolveClass method reads a single object
from the stream. If the object is a String (and the value of the java.rmi.server.useCodebaseOnly property is
 not true), then resolveClass returns the result of calling RMIClassLoader.loadClass with the annotated String
 object as the first parameter and the name of the desired class in the class descriptor as the second
parameter. Otherwise, resolveClass returns the result of calling RMIClassLoader.loadClass with the name of
the desired class as the only parameter.

從RMI marshal流中讀取的每一個(gè)class修飾器,resolveCalss方法從流中讀取一個(gè)單獨(dú)的對(duì)象。如果這個(gè)對(duì)象是個(gè)String(并且java.rmi.server.useCodebaseOnly的屬性值是true),resloveClass調(diào)用RMIClassLoader.loadClass,使用這個(gè)annotated的String對(duì)象作為第一個(gè)參數(shù),class修飾器重設(shè)想的名字作為第二個(gè)參數(shù),并返回結(jié)果,否則resolveClass只使用想要的名稱作為參數(shù)調(diào)用RMIClassLoader.loadClass,并返回結(jié)果。




3.5 RMI Through Firewalls Via Proxies

The RMI transport layer normally attempts to open direct sockets to hosts on the Internet. Many intranets,
however, have firewalls that do not allow this. The default RMI transport, therefore, provides two alternate
 HTTP-based mechanisms which enable a client behind a firewall to invoke a method on a remote object which
resides outside the firewall.
As described in this section, the HTTP-based mechanism that the RMI transport layer uses for RMI calls only applies to firewalls with HTTP proxy servers.

RMI傳輸層一般嘗試直接打開(kāi)Internet上的sockets,但是許多intranets,裝了防火墻不允許這么做.所以默認(rèn)的RMI傳輸提供另外一種基于http的機(jī)制允許客戶端在防火墻之后調(diào)用防火墻之外的遠(yuǎn)程對(duì)象的方法.
RMI傳輸層使用的基于HTTP的機(jī)制僅僅應(yīng)用于HTTP代理服務(wù)器的防火墻.


3.5.1 How an RMI Call is Packaged within the HTTP Protocol

To get outside a firewall, the transport layer embeds an RMI call within the firewall-trusted HTTP protocol.
 The RMI call data is sent outside as the body of an HTTP POST request, and the return information is sent
back in the body of the HTTP response. The transport layer will formulate the POST request in one of two
ways:
1.    If the firewall proxy will forward an HTTP request directed to an arbitrary port on the host machine, then it is forwarded directly to the port on which the RMI server is listening. The default RMI transport
layer on the target machine is listening with a server socket that is capable of understanding and decoding
 RMI calls inside POST requests.
2.    If the firewall proxy will only forward HTTP requests directed to certain well-known HTTP ports, then the call is forwarded to the HTTP server listening on port 80 of the host machine, and a CGI script is
executed to forward the call to the target RMI server port on the same machine.

為了在防火墻之外獲取,傳輸層把一個(gè)遠(yuǎn)程調(diào)用嵌入防火墻信任的HTTP協(xié)議.
遠(yuǎn)程調(diào)用的數(shù)據(jù)作為一個(gè)HTTP Post請(qǐng)求的body傳送出去.返回的信息則作為HTTP回應(yīng)body返回.傳輸曾必須規(guī)范POST請(qǐng)求在下面方式的一種:
1.    如果防火墻代理使用機(jī)器上任意一個(gè)端口轉(zhuǎn)交一個(gè)HTTP請(qǐng)求,則它會(huì)轉(zhuǎn)交給RMI Server上監(jiān)聽(tīng)的端口,在目標(biāo)機(jī)器上默認(rèn)的RMI傳輸層使用一個(gè)Server Socket監(jiān)聽(tīng),它能解釋和解碼內(nèi)部的在POST請(qǐng)求中的RMI調(diào)用.
2.    如果防火墻代理使用機(jī)器上不指定端口轉(zhuǎn)交一個(gè)HTTP請(qǐng)求,則轉(zhuǎn)交給監(jiān)聽(tīng)80端口的HTTP Server.CGI script將會(huì)調(diào)用同一臺(tái)機(jī)器上目標(biāo)RMI server端口.


3.5.2 The Default Socket Factory

The RMI transport implementation includes an extension of the class java.rmi.server.RMISocketFactory, which is the default resource-provider for client and server sockets used to send and receive RMI calls; this
default socket factory can be obtained via the java.rmi.server.RMISocketFactory.getDefaultSocketFactory
method. This default socket factory creates sockets that transparently provide the firewall tunnelling
mechanism as follows:
•  Client sockets first attempt a direct socket connection. Client sockets automatically attempt HTTP
connections to hosts that cannot be contacted with a direct socket if that direct socket connection results in either a java.net.NoRouteToHostException or a java.net.UnknownHostException being thrown. If a direct
socket connection results in any other java.io.IOException being thrown, such as a java.net.ConnectException
, the implementation may attempt an HTTP connection.

•  Server sockets automatically detect if a newly-accepted connection is an HTTP POST request, and if so,
return a socket that will expose only the body of the request to the transport and format its output as an
 HTTP response.



RMI傳輸實(shí)現(xiàn)包括java.rmi.server.RMISocketFactory一個(gè)擴(kuò)展,它是客戶端和服務(wù)器端發(fā)送和接收RMI調(diào)用默認(rèn)的資源提供者.默認(rèn)的Soket Factory可以通過(guò)java.rmi.server.RMISocketFactory.getDefaultSocketFactory方法獲得,默認(rèn)的socket factory創(chuàng)建sockets提供防火墻傳輸機(jī)制.如下:

•  客戶端sockets首先嘗試直接打開(kāi)一個(gè)socket連接.客戶端sockets自動(dòng)嘗試與主機(jī)上建立HTTP連接,如果直接soket連接返回的是java.net.NoRouteToHostException或者java.net.UnknownHostException的一種, 則說(shuō)明主機(jī)不能直接被soket直接接觸到.如果直接的socket連接返回的是一個(gè)其它的java.io.IOException,比如java.net.ConnectException,這個(gè)實(shí)現(xiàn)則會(huì)嘗試一個(gè)HTTP連接.

•  如果一個(gè)新的接受到的連接是一個(gè)HTTP POST請(qǐng)求,Server sockets能自動(dòng)觀測(cè)到,則返回一個(gè)socket,傳輸只暴露body的請(qǐng)求,并且作為一個(gè)HTTP response格式化它的輸出。


Client-side sockets, with this default behavior, are provided by the factory's
java.rmi.server.RMISocketFactory.createSocket method. Server-side sockets with this default behavior are
provided by the factory's java.rmi.server.RMISocketFactory.createServerSocket method.

客戶端的sockets的默認(rèn)行為由java.rmi.server.RMISocketFactory.createSocket方法提供.服務(wù)器端的默認(rèn)行為由java.rmi.server.RMISocketFactory.createServerSocket方法提供.


3.5.3 Configuring the Client

A client can disable the packaging of RMI calls as HTTP requests by setting the java.rmi.server.disableHttp
 property to equal the boolean value true.

設(shè)置java.rmi.server.disableHttp屬性為true,客戶端可以阻止RMI調(diào)用包裝成HTTP請(qǐng)求.


3.5.4 Configuring the Server

________________________________________
Note - The host name should not be specified as the host's IP address, because some firewall proxies will
not forward to such a host name.
________________________________________
1.    In order for a client outside the server host's domain to be able to invoke methods on a server's
remote objects, the client must be able to find the server. To do this, the remote references that the
server exports must contain the fully-qualified name of the server host.
Depending on the server's platform and network environment, this information may or may not be available to the Java virtual machine on which the server is running. If it is not available, the host's fully qualified name must be specified with the property java.rmi.server.hostname when starting the server.

For example, use this command to start the RMI server class ServerImpl on the machine chatsubo.javasoft.com:
   java -Djava.rmi.server.hostname=chatsubo.javasoft.com ServerImpl


________________________________________
Note – 主機(jī)名不能指定為IP地址,因?yàn)橐恍┓阑饓Υ聿荒苻D(zhuǎn)交給這樣一個(gè)主機(jī)名
________________________________________
1.    為了使服務(wù)器主機(jī)domain之外的客戶端能調(diào)用服務(wù)器端遠(yuǎn)程對(duì)象的方法,客戶端必須能找到這個(gè)Server,所以服務(wù)器端暴露的遠(yuǎn)程引用必須包含服務(wù)器主機(jī)的全名.

依賴服務(wù)器平臺(tái)和網(wǎng)絡(luò)環(huán)境,信息可能會(huì)不能到達(dá)服務(wù)器端運(yùn)行的JVM.這時(shí),必須在Server啟動(dòng)的時(shí)候,設(shè)置ava.rmi.server.hostname屬性為主機(jī)的全名.

例如,在chatsubo.javasoft.com機(jī)器上使用這個(gè)命令啟動(dòng)RMI server類ServerImpl.
java -Djava.rmi.server.hostname=chatsubo.javasoft.com ServerImpl


2.    If the server will not support RMI clients behind firewalls that can forward to arbitrary ports, use
this configuration:
1.    An HTTP server is listening on port 80.
2.    A CGI script is located at the aliased URL path
               /cgi-bin/java-rmi.cgi
This script:
*    Invokes the local interpreter for the Java programming language to execute a class internal to the
transport layer which forwards the request to the appropriate RMI server port.
*    Defines properties in the Java virtual machine with the same names and values as the CGI 1.0 defined
environment variables.
An example script is supplied in the RMI distribution for the Solaris and Windows 32 operating systems.
Note that the script must specify the complete path to the interpreter for the Java programming language on the server machine.

An example script is supplied in the RMI distribution for the Solaris and Windows 32 operating systems. Note
 that the script must specify the complete path to the interpreter for the Java programming language on the
 server machine.

如果這個(gè)Server不支持RMI 客戶端綁定隨意的端口,使用下面的configuration:
1.    一個(gè)監(jiān)聽(tīng)80端口的HTTP Server
2  .一個(gè)CGI script定位于別名的URL路徑
                    /cgi-bin/java-rmi.cgi
這個(gè)script:
*    為傳輸層調(diào)用一個(gè)本地的Java語(yǔ)言的解釋器執(zhí)行一個(gè)內(nèi)部class,為其轉(zhuǎn)交一個(gè)請(qǐng)求到一個(gè)合適的RMI Server端口.
*    在JVM中定義相同的名字和值的屬性作為CGI1.0定義環(huán)境變量.

在RMI中有一個(gè)針對(duì)Solaris和Windows32操作系統(tǒng)的script例子.注意在服務(wù)器端的機(jī)器上,script必須指定java解釋器的完整路徑.


3.5.5 Performance Issues and Limitations

Calls transmitted via HTTP requests are at least an order of magnitude slower that those sent through direct
 sockets, without taking proxy forwarding delays into consideration.
Because HTTP requests can only be initiated in one direction through a firewall, a client cannot export its
 own remote objects outside the firewall, because a host outside the firewall cannot initiate a method
invocation back on the client.

通過(guò)HTTP傳輸?shù)恼{(diào)用請(qǐng)求通常比直接通過(guò)socket傳輸慢的多,因?yàn)橥ㄟ^(guò)socket傳輸不需要考慮走代理的延遲
由于HTTP請(qǐng)求只能在一個(gè)方向上通過(guò)防火墻進(jìn)行初始化.客戶端不能在防火墻之外暴露自己的遠(yuǎn)程對(duì)象,因?yàn)榉阑饓χ獾闹鳈C(jī)不能初始化一個(gè)客戶端方法調(diào)用的返回



參考資料:
RMI lesson翻譯: http://www.tkk7.com/jht/archive/2007/05/09/116216.html
官方文檔:http://java.sun.com/javase/6/docs/platform/rmi/spec/rmiTOC.html