标题：JavaSpaces
概述
JavaSpaces是一种Java术语。JavaSpaces技术是进行分布式计算的一种简单机制，在分布式计算应用程序中，JavaSpaces 提供了对象的提供者和请求者可用来方便地进行通信的共享虚拟空间，这允许以Java对象的形式对任务、请求和信息进行简单的交换。Javaspaces提供了永久地建立和保存对象的能力，Javaspaces是建立在Jini之上的一种技术，它作为一种共享分布式通信的机制，还可作为一种存储对象的机制；JavaSpaces是一种Jini技术服务，这表示使用Javaspaces的开发人员也可以利用各种Jini服务比如说利用事务处理和通知等。JavaSpaces以一种非常简单的接口提供了这些功能，但是，有效地利用这种简单的接口需要大量的概念和工具。 
在分布式系统中，对象之间应当能够相互通信、共享信息。JavaSpace服务(JavaSpace service)利用对象的分布式存储(distributed repository)和三个简单操作(读、写和取)，实现了一个简单的、构建分布式系统的高层体系结构。JavaSpace服务通过Jini事务管理器和通知机制来支持事务，当与某个给定模板相匹配的条目写入JavaSpace服务时，通知机制能够通知某个对象。
JavaSpaces 概念及特性
JavaSpaces 概念可以从以下几个方面来理解JavaSpace概念：纯对象风格；作为Jini服务；具有共享分布式通信的机制； 对象存储机制。 
从纯对象的观点，所有JavaSpace都是我们所说的JavaSpace接口的实现。它确实是得出那些有趣结果的一个非常小的接口。从Jini的观点来看，JavaSpace是一个利用Jini基础结构并向其他Jini客户机和服务提供其功能的一个Jini服务。 
JavaSpaces提供了一种完成共享分布式计算的机制。这可能是它所提供的一种最重要的功能了。JavaSpaces还提供了一个非常有趣且简单的对象存储机制。这并不是说它们是一种对象数据库，但这确实是一个非常有用的功能。JavaSpace服务JavaSpace服务为Java对象提供分布式的共享存储器。任何与Java兼容的客户端都可以将共享对象放进这个存储器中。然而，对于这些Java对象有几个限制条件。首先，保存在JavaSpace服务的对象都必须实现接口Entry(在net.jini.core.entry软件包中)。JavaSpace服务Entry附加到Jini Entry的方式定义在Jini核心规范中。一个Entry对象能够有多个构造函数并需要相当数量的方法。其他的需求包括一个public的无参数的构造函数、public字段和非基本数据类型的字段。 
JavaSpace服务代理使用无参数的构造函数在反串性化过程中实例化匹配的Entry对象。所有的用于模板对Entry对象进行匹配的字段都必须是public的。Jini核心规范中定义，一个Entry对象不能包含基本数据类型的字段。这个对象类型的字段要求简化了匹配的模板模型，因为基本的数据类型不能有null值，该值在模板中作为通配符。 
同Jini一样，JavaSpace技术需要几个底层的服务。JavaSpace服务依赖于Jini查询服务，在需要事务时，必须启动Jini事务服务，JavaSpace服务还依赖于一个Web服务器和RMI活动守护程序rmid。JavaSpace服务的属性JavaSpace技术简化了分布式系统的设计与开发。一个JavaSpace服务有五个主要的属性： 1）JavaSpace服务是一种Jini服务。 2）一个条目将一直保存在JavaSpace服务中，除非它的合约到期，或是由某个程序从JavaSpace服务中取出。 3）JavaSpace服务定位对象的方法是将对象与模板进行比较。模板指定了JavaSpace服务比较各个条目的搜索条件。如果有一个或多个条目匹配模板，JavaSpace服务将返回其中的一个。 4）JavaSpace服务使用Jini事务管理器来支持操作执行的原子性。 5）JavaSpace服务的对象是共享的。程序可以从JavaSpace服务中读出或取得条目，改变这些条目的public字段，以及写回到JavaSpace服务供其他程序使用。永久对象仓库JavaSpaces的一个特点是对象数据仓库。写入一个空间的项都是正式的Java对象。 但请注意，JavaSpaces并不是一个对象数据库。Entry实例在位于JavaSpace中时并不是活动的，只是能够作为拷贝访问。这表示不能直接更改空间中的一个项。例如，如果在一个空间的某行中两次写相同的Entry实例，则此空间中将会有两个项。因此，空间中不存在维护项的对象标识的概念。共享分布式计算租用、事件和事务处理的产生是由分布式程序设计的特性所决定的。相对于一般的本地计算来说，分布  图1式计算环境中的基础环境易出错。JavaSpaces引入了一种不同的模型。JavaSpace：提供了进行通信的一种中介模型。图1示出这种模型。 
初看上去，这似乎在分布式系统中又引入了一个可能出问题的环节。但实际功能是分离了进程。不用操心特定进程通信的细节，进程1(上图1中)所要操心的是写一个项到JavaSpace，进程2无需关心项是怎样进入Javaspace的，它只要取走它们，然后做自己的工作即可；对进程进行分离有几个好处，如果进程2失  图2败，并不会影响进程1，进程1仍然能够继续完成自己的任务；如果需要添加另一个进程到图中(在图1所示的紧密耦合模型中)，必须更改一个或多个程序的代码，或者必须一开始就编写涉及多个进程的复杂代码，而在图2中要添加另一个进程只需在图中简单地加上它即可。 
在上图中，进程3可以很轻松地向空间写入项了。因为进程1不需要知道进程2的细节，所以添加进程3也不需要更改它，这里进程2并不关心空间中的项来自何处，它只需使用它们即可，这种松散的耦合模型对于降低分布式程序设计的复杂性特别有用。
JavaSpaces 技术
分布式环境中的很多应用程序和在本地环境下类似，需要持久地存储数据，JavaSpaces服务以完整的Jini服务的形式提供这一功能；和其他Jini服务一样，使用者可以通过查找过程使用其代理找到它，JavaSpaces采用了以Java为中心的策略，它不是数据存储服务，而是对象存储服务，也就是说，它保存完全的、有效的Java对象；事实上，它也只能保存Java对象，JavaSpaces彻底理解Java类型系统，可利用类型语义使需要存储、寻找和取出Java对象的应用更加自然贴切。JavaSpaces的起源创建JavaSpaces的很多工作是基于David Gelernter的早期研究，Gelernter是耶鲁大学的计算机科学家，他曾设计了一个称为Linda的系统，这个系统在很多方面都是JavaSpaces的前身。Linda中的中心概念是元组（tuple）和元组空间，元组是把数据组合在一起的集合，而元组空间是供应用存进和取出元组的“共享黑板区”。这两个概念很显然与JavaSpaces中的项目（entry）和空间（space）概念相仿，不过尽管JavaSpaces很大程度上继承了Linda，但二者还是有些重要的区别。
第一，Linda元组不具有Java语言提供的强类型，也就是说，尽管元组中单个的元素（element）可被赋以类型，但整个元组不行。JavaSpaces提供的强类型不仅可用于Entry对象，而且可用于Entry指向的对象。 
强类型对于JavaSpaces来说很重要，它使JavaSpaces可很好地满足那些希望使用Java平台强类型的应用。更进一步，JavaSpaces的Entry对象不仅可以使用强类型，而且它们可以进一步利用Java的类型系统，这意味着客户可基于超类关系进行搜寻，而Linda只允许值匹配。
第二，Entry对象在JavaSpaces中是真正的对象，也就是说，它们不仅可以有相关的数据，而且可以有方法。由于完整的对象可存储在JavaSpaces中，因此客户不仅可以取出“无生命”的数据，而且可以取出所需代码来操作这些数据。 
最后，JavaSpaces很好地遵循了Jini规范和范型。Linda系统一般是用一个很大的、单独的Linda元组空间，而Jini群体通常可以有多个活跃的JavaSpaces服务，每个服务都可以支持自己单独的对象存储区。JavaSpaces的Entry对象是由存储它们的客户租借的，因此Jini的自修复能力也很好地应用到这里。 
Java的兴趣引起人们对Linda沿续下来的系统产生了新的兴趣，其中之一是IBM研究中心的TSpaces系统。TSpaces在很多方面都与JavaSpaces相似，但要大得多。Tspaces支持通过下载的程序修改元组空间的行为，支持数据库风格的索引和查询，还允许用户对元组设置访问控制安全策略。对象的文件系统JavaSpaces的目标是提供"对象的文件系统"，也就是说，JavaSpaces可提供一种无所不在的、自然的方式来存储和使用对象，它的设计是为了自然地工作于用Java开发的面向对象应用程序。另外和文件系统相似的是，JavaSpaces可支持在应用之间共享对象，因此就像一个应用（或用户）可以把文件放到文件系统中众所周知的位置以供其他应用（或用户）取出一样，JavaSpaces可作为支持Java的客户和服务之间共享的通信中介。 
但通常的文件系统只存储"字节包"，如在UNIX和Windows系统中，共享文件甚至不与类型相关联。多数情况下，这取决于使用文件的应用及已建立的约定，把某种意义或解释与文件系统中被称为文件的"字节包"联系起来。 　　而JavaSpaces是面向对象的存储系统。JavaSpaces不是存储简单的无类型数据，它利用Java存储整个对象，以及作为Java对象所具有的好处：强类型、可移动代码、安全执行等。因此在JavaSpaces中，被存储的实体有实际类型，并且可以包含代码。 　　JavaSpaces的另一点不同在于寻找被存储实体的方式。在文件系统中，对先前存储数据的访问是通过命名，文件系统中的每个文件都有一个在文件系统中唯一的名称。若这个名称是被使用它的各方周知且认可的（比如C:\autoexec.bat或/dev/tty），则按照约定，它可以有特殊的属性并且可以被很多其他实体使用。文件系统中的搜寻通常是搜索文件名中的一部分或搜索文件的实际内容（适于部分情况如文本文件）。 　　在JavaSpaces中，名称并不重要。事实上，对象的"名称"只是可用来寻找对象的众多属性中的一个。我们可以基于对象的类、超类，或它们实现的接口来搜寻对象，也可以基于对象的属性搜寻对象-按照约定，任何属性都和名称一样对待。基于属性的搜寻如果对象不必用名字来标识它们，那么客户如何使用JavaSpaces来存储和找到对象呢？JavaSpaces使用与Jini查找服务基于属性的搜寻完全相同的技术，每个存储在JavaSpaces中的对象都必须实现net.Jini.core.entry.Entry接口，意思是它可以被解释为是其内部成员对象的强类型集合。事实上，JavaSpaces和Jini查找服务使用属性搜寻的唯一区别，就在于查找服务定义了一组模板如何与一组项目匹配的条件，而JavaSpaces只有匹配单个项目的工具。我们知道Entry是一个无方法的"标记"接口，对象可实现它，告诉系统这个对象的创建者知道此对象被用到查找服务的特殊方式（对象的成员被独立地序列化等）。Entry对象在JavaSpaces中也具有完全相同的语义：它们被当作是自己指向的公有、非静态、非最终、非变化对象的集合。每个Entry可通过与其成员对象匹配的"模板"被搜寻，搜寻时使用的模板可以基于类型或对象的值，支持"通配符"。 
由于相同的概念已被广泛地应用在Jini查找服务中，因此我们已经熟悉了它。尽管JavaSpaces使用不同的API集来存储、搜寻和取出对象，但它使用完全相同的基于属性的搜寻规则。它使用的API更适用于存储服务的需要。JavaSpaces编程模型JavaSpaces信奉的哲学是"少就是多"；使用JavaSpaces的编程模型很小，在JavaSpaces上可进行的操作只有四种： 
向JavaSpaces写入一个新对象； 读JavaSpaces中的一个对象； 取出JavaSpaces中的一个对象（相当于读并删除被读的项目）； 要求JavaSpaces在有与给定模板相匹配的对象被写入时通知请求者。 　　就这么多，实在不能再简化了。这种概念性的操作可通过net.Jini.space.JavaSpace接口中一组稍多些的方法被使用，这些方法为某些操作提供了重载的实现，以在某些方面加速空间的处理。所有这些操作都支持普通Jini中的租借概念，被存储的对象实际是租借的，客户必须为存储的对象续订租约，否则JavaSpaces将删除此对象。同样，JavaSpaces服务也租借事件注册，就像查找服务一样。所有这些操作都具有Entry参数，它们用来指定被存储的对象（写操作中），或指定被匹配的模板（在读、取出和通知操作中）。 　　下面来看一下JavaSpaces的接口，此接口net.Jini.space.JavaSpace由JavaSpaces服务的服务代理实现。和所有Jini代理一样，我们不知道（通常不必关心）服务代理如何实现此接口，特定的代理可能使用RMI或CORBA或原始套接字来与后端JavaSpaces通信，而服务可以由内存中的hash表或完整的数据库实现。不过有一点是统一的，它们的代理必须实现这个简单的接口，以使客户和其他Jini服务能以相同的方式使用它们。 JavaSpace实际的接口定义很简短紧凑，请参阅程序清单1：
﻿程序清单1  Javaspace.java
import net.jini.core.entry.*；
import net.jini.entry.*；
import net.jini.core.transaction.*；
import net.jini.core.event.*；
import net.jini.core.1ease.*；
import iava.rmi.*；
public interface JavaSpace{
Lease write(Entry entry，Transaction txn，long lease)
throws TransactionException，RemoteException；
long NO_WAIT=0；
Entry read(Entry tmpl，Transaction txn，long timeou：)
throws UnusableEntryException，TransactionException，
InterruptedException，RemoteException；
Entry readlfExists(Entry tmpl，Transaction txn，
long timeout)
throws UnusableEntryException，TransactionException，
InterruptedException，RemoteException；
Entry take(Entry tmpl，Transaction txn，long timeout)
throws UnusableEntryException，TransactionException，
InterruptedException，RemoteException；
Entry takelfExists(Entry tmpl，Transactzon txn，
long timeout)
throws UnusableEntryException，TransactionException，
interruptedException，RemoteException；
EventRegistration notify (Entry tmpl，Transaction txn，
RemoteEventListener listener,
long lease，
MarshalledObject handback)
throws TransactionException，RemoteException；
Entry snapshot(Entry e)throws RemoteException；
)正如所见，程序清单1中列出的七个方法可用来提供某些非常复杂的行为的机制。不过，在遇到复杂问题时，最好从简单的地方入手。幸运的是，这些接口都很简单。
1）Entry 在学习实际的方法前，应该对Entry(项)类给予某种特殊的关注。下面是net.jini.core.entry.Entry的接口定义： 
﻿package net.jini.core.entry；
public interface Entry extends java点io.Serializable{
}在建造一个实现项的类时，需要遵循以下几条规则：Entry子类的每个字段必须是公共的(字段可以是非公共的，但不能把它们保存在空间中)；字段不能为简单字段，它们必须是对象；字段必须是可串行化的；必须提供一个公共的无参数的构造函数。
2）Read read方法用于在JavaSpace中查找项。从本质上来说，它提供了一种搜索JavaSpace的方法。 
﻿Entry read(Entry tmpl，Transaction txn，long timeout)
throws UnusableEntryException，TransactionException，
InterruptedException，RemoteException；第一个参数是一个项，用作执行搜索的模板，如果项的某个字段为空，则空间中相同类型的任意项内的同一个字段都将匹配，这里"类型"一词用来表示匹配项可以是与模板相同的类或者是模板的子类。如果模板中的一个字段不为空，则相同类中其他项内的字段必须精确匹配；如果找到一个匹配，就会返回匹配项；如果空间中有不止一个匹配项，则空间可以返回任意匹配项；至于返回哪个项不能保证，这表示不应该指望读项的顺序会有什么对应关系(如到达的顺序等)；第二个参数提供了一个Transaction实例，应该在其下执行读操作； 最后一个参数为长整型，以毫秒为单位，此值说明在read方法中对于匹配项的出现在空间中要等待多久。这表示，如果一个匹配项在第一次调用read方法时不在空间中，则read方法将等待此项被添加到空间中，等待时间为此参数给出的超时值，如果等待时间超过超时值后还没有项匹配，则返回空。 3)readlfExists 　　readlfExists方法是一个非常类似于read的方法，它具有与read完全相同的参数和返回值；不过，readlfExists在这些参数的使用上稍有不同，它也是用来搜索空间的，而且使用相同的匹配模板实例的规则，read和readlfExists的不同之处在于超时值的处理。 　　readlfExists方法试图匹配作为第一个参数传入的模板项，如果未匹配，它立即返回，而不是像read方法那样等待匹配项。既然它立即返回，那么还要超时参数干什么呢? 这个问题涉及Javaspaces怎样处理事务，一个匹配项可能位于空间中，但可能在至今尚未完成的事务处理下写过，这表示此匹配项并不真正对readlfExists方法可见，超时参数指出readlfExists等待完成此未结束的事务处理要等多久。因此read方法要等待直至找到匹配项或超时期满，而readlfExists方法仅在恰好存在与未结束事务处理之下的匹配项相同的匹配项时等待。 4)take 　　take方法也具有与read方法相同的参数和返回值。它使用项模板的相同匹配规则，其超时值与read的超时值类似，即等待直到匹配项出现为止。但其重要的差别在于，如果找到一个匹配项，不仅返回给方法的调用者，而且还从空间中删除它。另外，如果多个客户机调用take方法且它们匹配空间中相同的项，则只有一个客户机取得该项，而其他客户机得到空返回值。 5）takelfExists 　　就像readlfExists方法对应于read方法一样，takelfExists方法对应于take方法，即它的超时参数指出等待具有一个匹配项的未结束的事务处理完成要等待多长时间。 6）write write方法用于把项放入空间。
Lease  write(Entry entry，Transaction  txn，long lease)
throws TransactionException，RemoteException；﻿write以希望放入空间的项作为第一个参数。请注意，任意种类的项都可以写入一个空间。write方法也使用write所属的Transaction实例以及一个租用参数，write方法的返回值为一个Lease实例。这允许调用者对将项保留在空间中有某些控制权。 
7）notify 　　notfiy方法提供感兴趣的项被写入某个空间时到得通知的异步机制。
﻿EventRegistration notify (Entry tmpl，Transaction txn，
RemoteEventListener listener,long lease，MarshalledObject handback)
throws TransactionException，RemoteException；第一个Entry参数指出匹配空间中的项时使用的模板，匹配规则与read方法的相同，与read方法不同的是notify指出调用者对只要写匹配项就得到通知感兴趣，而不是对调用时在那里的项感兴趣。RemoteEventListener参数告诉空间送回事件给谁，在写一个新项到匹配模板的空间时，此空间发送一个事件到RemoteEventListener，以便它可以处理此事件；Handback参数作为事件数据的组成部分被发送到监听程序，这给notify方法的请求者提供了与Listener实例通信的一种途径；Lease参数指出调用者在接收通知时等待多长时间，时间以毫秒表示；EventRegistration返回的值为notify方法的调用者(如Lease实例)管理其注册提供某些信息。 
8）snapshot 它是一种优化空间性能的方法。 
Entry snapshot(Entry e)throws RemoteExceptlon；﻿在利用相同的模板项对一个空间重复调用方法时，snapshot方法有助于提高程序的性能。Snapshot工作的方式是你对传递希望优化性能的模板的空间调用它， 调用之后返回一个Entry实例，此Entry实例代表传入的项。基本上，空间会记住此新项实际上是旧项。在传递的这个新代表项调用空间时，避免了串行处理的大量开销。在模板项很大且串行化代价很高时，这样做可以极大地改善性能。 
有一件需要注意的重要事情是，这仅对在其上调用snapshot方法的空间有效。如果在另一个不同的空间上调用某个方法并传递快照项，则新空间将不承认快照项代表原模板项。另一个要点是取回的项与传入的项根本不同。不应该将新项与已经拥有的任何项进行比较。 
JavaSpaces技术的应用
简介Jini提供了在分散式环境中寻找（ look-up）、注册（ registration）、租借（leasing）等功能。而 JavaSpaces则负责管理分散式物件的处理程序（ processing）、分享（sharing）、以及流通（migration ）等。因此 Jini 与 JavaSpaces 彼此存在著相互合作的关系。简单的说，JavaSpaces就好像网路上的一个市场，它提供一个简单、快速、统一的介面，让网路上分散的资源可以被分享、协调与流通 。 
对于要存储对象或使对象可被其他对象使用的很多应用，JavaSpaces技术具有立竿见影的效用。不过也可以通过其他方式使用JavaSpaces，它可以作为一种新的分布式系统编程范型的基础。这是Linda的最初目的，而Linda正是JavaSpaces的基础。尽管Linda可以用做简单的存储引擎，但它的真正目的是提供一种新的用于创建分布式应用的模型。在这种新模型中，分布式系统的创建将使对象在应用之间"流动"，通过中心的Linda元组空间进行协同。这种思想不是为新的分布式应用创建定制的远程通信接口或协议，而是应用可根据它们写入元组空间及从元组空间中读出的对象集合来定义。如果用Java术语描述它，就是说不是为每个新任务定义或细化新的RMI远程接口，而是JavaSpaces接口将成为应用之间交互的公共API，应用将定义自己的Entry对象集，并给这些对象赋以自己的语义。 　　Javaspace是一个Jini服务，它提供一种共享分布式对象仓库。JavaSpaces是用 Java所发展的技术，并且以RMI实作其网路通讯的功能，一般应用在n-tiers 架构的中间层（middle tiers）。JavaSpaces虽然能提供求者与供应者之间查询与沟通的机制，但它并不是资料库，而是以简单的messaging system为基础，进而提供更强大的功能。除了在Jini应用之外，JavaSpaces技术也可被应用在其它系统与服务中，如：Workflow systems 、Customer management systems、Supply chain management 、Intelligent rich data distribution、 Trading services 、Auction systems 、Resource allocation and management systems、Agent Systems、以及 Publish and subscribe services等，现在我们来简要地介绍一下几个可以使用Javaspaces的领域：信息共享Javaspaces可以共享对象。因此，许多Javaspaces的应用程序可以做这个工作是不奇怪的。 可通过空间方便地交换信息。写到一个空间的每个项都可以从该空间的任一个客户机读出。 读取者和写入者不需要互相了解。所需知道的只是何种项放入了此空间。例如，空间可在聊天或通话系统中使用，这种系统已经变得非常流行了。其中，空间被用作共享的留言板，多个客户机可以写入和读取消息。计算服务除共享数据以外，Javaspaces的一个非常有意思的用途是共享分布式系统计算。 一般在这种用法中，计算一个(或多个)问题块的产生器可能很昂贵，但这种问题可以分成并行任务。产生器把问题块发送到某个JavaSpace。然后，运行在分离的机器上的该空间的客户机使用这些块，进行计算并将完成了的块返回给JavaSpace。然后再把这些完成的块装配起来。工作流JavaSpaces也很适合于管理工作流环境。可以把工作流环境与纯计算服务环境区分开来，在工作流环境中所调度的工作可以由人而不是纯计算完成。