MPEG-J综述

1.MPEG-J简介 MPEG-J是MPEG-4 Version 2中对MPEG-4做的扩展,它是一种灵活的编程控制机制。MPEG-J允许在MPEG-4内容中使用Java类。MPEG-J代表了一个视听会话,当这个会话在接收终端表现时,可以适应终端的操作特点。例如,在资源有限和资源可变的情况下可以避免服务质量剧烈变化;另外,MPEG-J具有响应用户交互的能力,允许对接收终端进行程序控制,这极大地方便了诸如机顶盒、交互游戏和移动AV终端等应用的集成。这些特点使对本地和远程终端的高层交互控制成为可能。Java代码能够创建和修改场景,完全参与场景交互,控制解码器。Java代码也可以产生GUI组件,直接实现应用功能。但是,为了确保高质量解码,Java代码不能参与实时媒体的数据流,例如,实现一个视频解码器等。 2.MPEG-J系统结构 MPEG-J是一套程序控制系统,它定义了MPEG-4媒体播放器和Java代码之间的互操作接口。通过把MPEG-4媒体和安全的可执行代码结合起来,内容创建者能够在媒体数据中嵌入复杂的控制机制,实现对视听会话的智能管理。Java代码是以独立的基本码流传送到MPEG-4终端的。在接受端MPEG-J代码将直接到达MPEG-J运行时间环境,MPEG-J程序可以访问MPEG-4播放器的各种组件。MPEG-J软件体系结构如下图: 图1中的体系结构考虑到了底层平台上的可用资源。这个结构包括了独立组件的隔离、接口设计以及组件之间互操作的特性。这些组件包括: 解码和显示资源:我们认为解码和显示资源是有限的。这个组件对播放器中这些动态和静态资源的访问进行了抽象。 解码器:这个组件抽象了用于解码接收媒体流的媒体解码器,以及对解码器的编程控制和操纵。 网络资源:这个组件抽象了对媒体码流的控制,也抽象了传输和显示码流的管道。 场景图:每个MPEG-4会话都有一幅场景图,场景图在时间和空间上代表了视听对象。这个组件抽象了对场景图的访问和控制。 MPEG-J系统中定义的MPEG-J应用程序接口(MPEG-J API)就是反映上述组件的接口。图2表示了一个控制MPEG-4解码的MPEG-J播放器。图2中的下半部分是MPEG-4解码器模型,相当于图1中的显示引擎(Presentation Engine)部分。图2中的上半部分表示了MPEG-J系统对显示引擎的控制,相当于图1中的应用引擎部分(Application Engine)。 3. MPEG-J会话 只有当接收到并且将要执行MPEG-J应用程序的时候才需要启动MPEG-J会话,这可以通过一个或多个MPEG-J基本码流来识别。 3.1 MPEG-J会话的启动 当MPEG-4播放器接收到一个MPEG-J对象描述符的时候就初始化MPEG-J会话。播放器要执行如下步骤: 播放器通过DMIF通道打开MPEG-J基本码流。MPEG-J基本码流与其他MPEG-4码流相似,都是经过同步层打包的码流。 播放器把访问单元(Access Units)投递给类载入器,由后者载入类。 MPEG-J码流中的一个入口点(run方法)可以不只有一个类。每次接收到一个包含入口点的类,在该处都要启动一个执行线程。 使用MPEG-J应用程序接口控制MPEG-4播放器的MPEG-J应用程序既可以在本地也可以在远端。在远程应用的情况下,远端的应用程序在MPEG-J基本码流中接收,它必须实现MPEGlet接口——MPEGlet是通过码流传送到客户端的Java MPEG-J应用程序。本文下面部分讲述的MPEGlet的生命周期和安全模型不适用于本地的应用程序。 3.2 MPEG-J基本码流和名字空间 3.2.1 MPEG-J基本码流 MPEG-J数据由类文件和对象数据组成,通过媒体流以MPEG-J基本码流的形式传送到MPEG-J终端。在一个MPEG-J码流中的类文件和所有相关的数据可以随意地打包在一起。 3.2.2 MPEG-J码流的名字空间 MPEGlet的名字空间从MPEG-J基本码流的对象描述符中继承而来。与场景图中的节点标识相类似,在一个基本码流中的MPEGlet所使用的所有标识符都在这个基本码流及其对象描述符的名字空间中解释。因而,所有限制内联场景的名字空间的规则对MPEG-J会话同样起作用。 3.2.3 MPEGlet的生命周期 MPEGlet的生命周期与applet非常相似。MPEGlet接口拥有init()、run()、stop()和destory()方法。当接收到MPEGlet的时候,会在Strat-Loading时间戳之后和Load-By时间戳之前的时间段内加载MPEGlet。在由Load-By时间戳确定的时刻,执行MPEGlet的init()方法。初始化MPEGlet之后,run()方法作为一个独立的线程被调用。与applet类似,在MPEGlet接口中要定义stop()和destory()方法。如果MPEG-J播放器在码流中接收到另外一个MPEGlet,新接收到的MPEGlet要作为一个不同的线程来初始化和启动。 3.2.4 MPEGlet的安全模型 MPEGlet的安全模型与applet的安全模型极为相近。但是,在播放器上执行的安全管理器能够添加和减少安全限制。缺省情况下,所有应用于applet的安全限制也可以应用于MPEGlet。MPEGlet的这些缺省的安全限制如下: · MPEGlet不能加载联接库或者定义自然方法。 · MPEGlet只能使用由底层平台提供的它自己的Java代码、MPEG-J APIs以及Java APIs。 · 通常MPEGlet不能读写运行这个MPEGlet的主机的文件。 · MPEGlet不能在其运行的主机上启动任何进程。 · 除了通过终端能力接口,MPEGlet不能读取系统属性。 4. MPEG-J数据的传输 MPEG-J应用程序是以MPEG-4基本码流的形式传送到MPEG-4播放器的。MPEG-J数据可以是类、序列化的对象,或者其他任何相关数据。序列化的对象和其他辅助数据要与能够处理这些数据的类在一起。 MPEG-J数据(类或者对象)必须要实时的传送给播放器。为了保证这一点可以使用Java码流头标识。在每个文件或对象数据传递到同步层之前都要携带这种头标。经过同步层打包之后,可以使用任何实时传输机制,如FlexMux、RTP甚至是MPEG-2传输码流来传输这些数据。 4.1 丢包 传输过程中的丢包问题会给Java程序的执行造成麻烦。解决这一问题的可以采用如下方法: 在没有上行通道的情况下,以固定的时间间隔重传整个类。这有助于实现随机访问。然而,如果客户数量很多或者类很大的话,这种方法是不可取的,应该禁止重传。 如果有上行通道,可以通知服务器重传已经丢失的包。有一些错误恢复方案可以恢复部分丢失的数据,例如前向纠错方案。 MPEG-J播放器并不处理丢包问题,它认为传输层是足够可靠的,确保不会丢包。 4.2 类依赖 如果一个类依赖于其他类,那么必须在加载这个类之前加载它所依赖的类。这就像在实例化一个对象之前,必须下加载这个对象的类一样。做到这一点的方法之一是使用封装机制,如JAR,把所有相关的类文件封装在一起。但是,这种方案并不好,特别是在传输通道不可靠的情况下,仅仅一个信息包丢失就会导致整个包丢失。在Java码流头标中提供了一种简单的类依赖机制。某个类依赖的所有类都列在这个类文件的头标中。在加载这个类之前需要先加载所有它依赖的类。 4.3 MPEG-J中的时间戳 在同步层的SL头标中定义的解码时间戳(DTS)和合成时间戳(CTS)也用于适时的传递MPEG-J基本码流。除此之外,MPEG-J码流中还有两个十分重要的时间戳: Start-Loading时间戳:这个时间戳指示了启动加载一个类的过程的时间。这个时间戳对于避免名字空间冲突和资源冲突是十分必要的,它也保证了需要载入类的资源载终端是可用的。 Load-By时间戳:这个时间戳指示了在MPEG-J终端应该加载一个类的时间。如果这个类实现了MPEGlet接口,在同一时刻也要初始化这个类(通过运行init()方法)。初始化之后,MPEGlet作为一个独立的线程运行(执行run()方法)。 Start-Loading时间戳和Load-By时间戳定义了一个加载类的时间窗口。这个时间窗口有助于解决类之间依赖关系。如果这两个时间戳之间的时间窗口变得足够大,就可以避免由于在不同客户终端上加载时间不一致的问题。另外,如果传输通道不可靠,也可以增大这个窗口保证重传。在这种机制下,类加载的顺序可以与类到达的顺序不同。 4.4 MPEG-J码流标志头 4.4.1 JavaStreamHrader 4.4.1.1 语法

ligned(32) class JavaStreamHeader{ 
bit(2) version; 
bit(1) isClassFlag; 
bit(13) numReqClasses; 
bit(1) isPackaged; 
bit(3) compressionScheme; 
bit(12) reserved; 
JavaClassID classID; 
JavaClassID reqClassID[numReqClasses]; 
} 

4.4.1.2 语义 version:版本号,目前的值为00。 IsClassFlag:把该值设为1,表示码流的有效负载是一个类;把该值设为0表示码流的有效负载不是类,而是可访问的MPEGle的内容这些内容可能是java对象或者其他数据。 numReqClasses:加载这个类之前需要的类的数目。 isPackaged:该值为0,表示是单一类文件,不是包。该值为1,表示是由多个类文件组成的包。 compressionScheme:确定码流压缩使用的方案(000表示没有压缩;001表示使用ZIP压缩,010——111由ISO保留)。 reserved:ISO为将来使用而保留。目前应为0xFF。 classID:类或包的识别信息。JavaClassID的类型定义如4.4.2所示。 reqClassID[n]:n个必需类的识别信息。 4.4.2 JavaClassID 4.4.2.1 语法 aligned(32) class JavaClassID{ bit(16) length; bit(8*length) ID; } 4.4.2.2 语义 length:ID的字节数。 ID:标识类的可变长字符串。这个字符串要填充,使得ID长度域和ID域的总的长度是32比特的倍数。 5.MPEG-J 应用程序接口(MPEG-J API) 程序包是实现应用程序接口的一种组织方式。MPEG-J API分成以下五类程序包: org.iso.mpeg.mpegj.mpegj org.iso.mpeg.mpegj.scene org.iso.mpeg.mpegj.resource org.iso.mpeg.mpegj.network org.iso.mpeg.mpegj.decoder 5.1 MPEG-J(org.iso.mpeg.mpegj) MPEG-J终端类(MPEG-J Terminal)提供了在接收终端运行的各种管理器的信息。每个MPEGlet或者应用程序一旦被加载的时候都要实例化一个新的MPEGjTerminal。这个类含有访问所有管理器的方法。管理器包括:场景观管理器(SceneManager)、资源管理器(ResourceManager)和网络管理器(NetworkManager)。 ObjectDescriptor,ESDDescriptor和DecoderConfigDescriptor接口也是org.iso.mpeg.mpegj.mpegj程序包的一部分。这些接口提供了对相应描述符的访问,通过这些接口可以获取关于节点、基本码流及其类型的信息和解码器的信息。 5.2 Scene API SceneGraph API提供了一种机制,通过这种机制MPEG-J应用程序可以访问和操纵BIFS场景。这是一种低级接口,它允许MPEG-J应用程序监视场景中的事件,可以按照预定的方式修改场景树。MPEG-J应用程序也可以创建和操纵节点,但是MPEG-J应用程序只能访问由DEF示例的节点的域。 这个接口是MPEG-J场景图管理器的最低层。接收终端只需要实现这个包就可以使MPEG-J绑定于初始场景其他类库可以完全用java定义,在更高的层次上访问和控制场景。 5.3 Resource API 程序的执行要与终端的配置和终端的执行能力相一致。MPEG-J程序需要了解其运行环境,以便于调整它自己的运行和在MPEG-4终端上配置和运行的各种组件的执行。这个接口在org.iso.mpeg.mpegj.resource程序包中定义,用于监视系统资源、使用事件机制监听例外并且处理这些不可测的事件。资源包有助于MPEG-4会话调整自身来适应各种终端资源。这个包的主要组成部件是资源管理器、事件模型、用来监视终端动态和静态能力的能力管理器,以及终端部件管理器。 5.4 Decoder API Decoder API实现了对一个MPEG会话中所有已经安装了的解码器的基本控制。可以通过资源管理器接口访问与特定节点相关的解码器。MPDecoder是抽象了绝大多数普通解码器的一种接口。 MPDecoder应用程序接口是解码器启动、停滞、暂停和继续。它也实现了把码流和一个解码器关联以及取消这种关联。它也可以获取当前相关联码流的描述符。 5.5 Net API 网络接口目的在于控制MPEG-4播放器的网络组件。通过这些接口,java应用程序能够与网络实体进行交互。由于MPEG-J 网络接口所提供的抽象级别,应用程序网络情况的具体细节。 为了避免结构不一致和工具重复,MPEG-J 网络接口不允许完全,任意地使用DMIF和同步层。目前网络接口的功能主要可以分为两部分: 网络访问:为了获取MPEG-4播放器使用的DMIF资源的统计信息,执行对网络模块的访问。这个能力是很重要的特征。 通道控制: 一种简单的通道控制机制。使用这个机制MPEG-J应用程序能够暂时打开或关闭现存的基本码流通道,而不会对播放器的其他部件产生任何负面影响。这一特性使得MPEG-J有能力在资源有限或者资源情况随时间变化的情况下,实现缓慢衰减,避免服务质量剧烈变化。 MPEG-J标准中定义了几百个应用程序接口,本文就不加以详细描述了。具体细节可以查阅参考文献[1]。 6.总结 MPEG-4的其他组件是由参数控制的,而MPEG-J是由程序控制的。MPEG-J为MPEG-4播放器Java程序代码的互操作定义了一系列编程接口。这就为在MPEG-4播放器中执行Java程序提供了可能。把MPEG代码和Java结合起来,可以为MPEG-4添加更丰富的内容。MPEG-J一定会成为实现交互技术的主要手段,而且会渗透到信息家电、机顶盒、3G移动通讯中去。 <淘宝热门商品:
 

IP卡/网络电话/在线影音充值 

SKYPE官方代理商在线充值

 

 

糊涂乖宝☆电子城


来源:程序员网

小小豆叮

面向对象编程:Java collection更有效管理elements

Sets 在Java Collection结构中,一个set就是众多元素中的一个collection,它确定了含有等同元素的精确的set模型,Set界面拓展了collention界面,意思就是说你可以在set中增加Object、删除object以及重新迭代等等。Set界面增加了两种名称均为排列的方法,而且可以把一个set转换成一列objects。 SortedSets SortedSets是实现按从小到大顺序排列元素这一迭代过程的set。Set中的元素都按自然顺序或者比较法进行分类。 Comparators Comparators是定义比较函数或等函数的界面,这样运行它的object结果是实现比较或等价功能,Comparators被传递给分类法来控制众多元素的分类程序。 Maps 与Set不同,Map并不是由Collection生成,相反,它提供了用某些键输入、输出值的界面,与java.util.Hashtable非常类似。 Map是包含一列键/值对的对象,Map不包含复制键,而且每个键也只能有一个值,Map可以实现恢复一套键、一组值以及一系列mapping的功能。 Sorting 对于collection结构有两种基本的分类方式 可以采用Collection类中两种静态法的任意一种运行列表界面来对Object进行分类。一种方法是获得运行比较界面的列表参数,另一种方法就是获得列表参数、比较参数并把采用比较对象的列表元素进行分类。 还可以把比较界面功能加到Collention类中,在类中加入了比较法,得到的结果就是从第一个参数中减去第二个参数,然后把Collection对象传递给运行比较界面的对象。 表A中的例子证明了对MySortedMapComparator对象进行分类的比较界面。 SortedMaps SortedMaps就是能够提供按从小到大排列元素功能的map,这些元素都按自然顺序或者比较法进行分类。见表B中的例子。 Sorting it all out Java Collection结构为表示分类集合和未分类集合的核心Java APIs增加了兼容的标准API。因为Collection结构的API都是相互兼容的,因此一旦学会了结构中的一部分,就会理解很多概念。这样就会让你少走很多弯路。下一篇文章中将要开始讨论Java平台的输入/输出系统。 <淘宝热门商品:
 

50.00 元 

黑头粉刺净 扫光黑头粉刺顽痘 卖疯了

 

198.00 元 

08秋款欧洲正版G-star双排扣夹克外套 超好


来源:程序员网

小小豆叮

win2000server install j2ee


 



一、环境配置 
1、WIN2000SERVER或NT4,最好128M以上内存 
2、正确安装了JDK 
有关JDK的安装请参考相关文章,只有正确安装了JDK,才能确保J2EE的正常运行 
3、下载j2sdkee-1_2_1-win.exe 和 j2sdkee-1_2_1-doc-win.exe 开发文档 
相关网址:http://java.sun.com/j2ee/ 

二、安装并配置J2EE 
1、双击j2sdkee-1_2_1-win.exe开始安装,安装路径默认是C:\j2sdkee1.2.1
 为了配置方便指定为 C:\j2ee ,你也可以指定自己的路径。 
    2、安装成功后将开发文档安装在J2EE\DOC目录下,当然,
没有文档J2EE一样可以正常工作,该文档只是做为一个非常好的帮助,
就像JAVA中的API一样,我们的例子就是从中选出的。 
    3、配置环境变量: 
      开始->设置->控制面板->系统->高级->环境变量->系统变量 
      新建:JAVA_HOME:C:\JDK   ------C:\JDK是你安装JDK的目录 
      新建:J2EE_HOME:C:\J2EE   ------C:\J2EE 是你安装J2EE 的目录 
      追加:CLASSPATH:C:\J2EE\lib\J2EE.jar;.; 
      这里的C:\J2EE是安装的根目录,
如果你安装目录不是C:\J2EE,请将C:\J2EE换成你的安装目录。 
三、一个J2EE application client 的简单例子 
   1、启动J2EE 
    打开一个DOS窗口,在C:\J2EE\BIN 目录下运行J2EE -verbose ,
出现下列信息: 

J2EE server Listen Port: = 1049 
Naming service started: :1050 
Published the configuration object ... 
Binding DataSource, name = jdbc/Cloudscape, url = jdbc:cloudscape:rmi:Cloudscape 
DB;create=true 
Web service started: 9191 
Web service started: 8000 
Web service started: 7000 
J2EE server startup complete. 
    启动成功!在以后的运行中不要关闭该窗口 
    在IE浏览器中访问HTTP://localhost:8000 可以看到默认的主页信息。 
<淘宝热门商品:
 

3C数码配件 

家倍乐床上笔记本电脑桌专利厂家批发零售店

 

198.00 元  

野葛根丰胸胶囊 植物萃取 天然健康


来源:程序员网

小小豆叮

用Java实现基于CORBA的自动负载均衡

用Java实现基于CORBA的自动负载均衡 陈亚奇 王红霞 2002-4-18 14:39:07 -------------------------------------------------------------------------------- 负载均衡 负载均衡是分布式计算中的一个重要内容,它的主要目标在于均衡所有结点上的负载,以使得所有结点上的负载基本相等,这种相等并非简单的任务数目相等,而是依据这些异构结点的性能分派的加权相等。 负载分配算法大体上可以分为静态、动态和自适应算法三类。静态负载分配算法根据已有的有关任务的信息,通过某个算法来确定任务的分配,它不使用系统状态信息来决定负载的分配,这对一些应用具有较高的效益。动态分配算法通过交换系统的状态信息决定系统负载的分配,具有超过静态算法的执行潜力。它能够适应系统负载变化情况,比静态算法更灵活、有效。由于它必须收集、储存并分析状态信息,因此动态算法会产生比静态算法更多的系统开销,但这种开销常常可以被抵消掉。自适应负载分配算法是一类特殊的动态算法,它们通过动态地改变其参数、策略来调节其活动以适应变化的系统状态。 动态负载分配算法按照集中程度可以分为集中式、完全分布式、层次性或它们中的一些结合算法。在动态集中式负载均衡系统中,全局负载信息收集在一个结点上,任何结点的负载变化信息都传给这个结点,负载均衡的所有决定由它做出。这种方式的好处在于能够以较少的开销收集全局信息,挑选出最佳结点执行任务,并且可以扩充到较大的网络计算系统。在完全分布式负载均衡系统中,每个结点保存相邻结点或系统中部分结点的负载信息,相互合作做出各自的负载分配。这种策略实现比较简单,并且经过一段时间后,可以选择到较合适的结点执行任务,缺点是不能获得最佳结点分配负载,很难扩展到成千上万个结点的网络计算系统。层次性方法是根据集中式、分散式方法的优缺点结合而成的一种负载均衡算法。它将系统分成层次性的子系统,在不同层次上特殊的结点作为负载均衡决策的控制结点,以分散其集中方式控制整个系统的负载均衡,它和网络拓扑结构有很强的相关性。 分布式计算 简单地说,分布式计算就是两个或多个软件互相共享信息,分散的计算资源通过分布式计算可以形成强大的计算能力。这些软件既可以在同一台机器上运行,也可以在通过网络连起来的几台不同的机器上运行。绝大多数分布式计算是基于客户机/服务器模型的。在客户机/服务器模型内,有两类主要的软件,客户机软件,它提出信息或服务的请求;服务器软件,则提供这种信息或服务。分布式计算具有共享稀有资源、在不同机器上平衡计算负载等优点。 目前比较流行的分布式计算方案为CORBA(Common Object Request Broker Architecture,通用对象请求代理体系结构)。CORBA由OMG(Object Management Group,对象管理组织)提出,已得到业界的广泛认可,获得了广泛的应用支持。本解决方案即采用了CORBA技术。 CORBA使用代理器ORB(Object Request Broker,对象请求代理)来处理系统中客户机与服务器之间的消息(称为请求)。ORB提供客户程序与服务程序之间的通信连接。当客户程序发出请求时,ORB查找对象的实现,将请求交给该对象(并在需要时激活对象),并将响应返回给客户程序。客户机无需知道服务器是哪个,身处何处,发送请求及返回结果的工作全部由ORB完成。ORB能选中一个最符合客户机请求的服务器,并把客户机所看到的接口从服务器的实现中分离出来,接口与实现分离的好处是可以采用灵活的、搭积木式的开发方法,实现对客户隐藏服务器的变化。只要接口及其行为没有变化,就可以构造一个新的服务器或修改已有的服务器而无需改变客户机。 实际问题 在油藏描述中有一类问题为地质统计分析,计算耗时很长(用工作站进行一次最简单的计算约耗时30分钟)。已有的计算程序是为单机而开发,生成的结果数据文件数据量很大(300002行,8Mb)。为了提高分析质量,现场多采用选用不同参数多次分析计算,然后对所有结果文件的对应位置数据取平均值的做法,非常费时费力。 为了解决这一难题,作者采用了基于CORBA的分布式计算技术。首先对原有非CORBA兼容程序进行封装,使其能被服务器对象的方法所调用,从外界看好象是服务器对象的方法一样;然后将计算程序—服务器程序对分别安装到网络中的几台工作站上,构成服务对象组;最后在网络中的一台微机上安装客户软件和ORB,即构成了一个完整的CORBA应用系统。在该系统中,操作者在客户程序中输入计算参数,通过ORB依次使其它工作站上的服务器程序启动计算软件进行分析计算,并将计算结果由服务器程序通过ORB回送给客户程序,由客户程序进行结果处理。 在上述过程中,最为关键的操作为ORB确定下一个请求时要启动的服务器,在各服务器节点间平衡负载,以减少任务响应时间,提高计算资源利用效率。这一工作需要用到CORBA的一个特性——自动负载均衡。 CORBA的ORB提供了基本的负载均衡功能,该功能的提供是基于动态集中式负载分配算法。服务器端建立服务器对象,然后向ORB注册,这样便形成了网络中所有可用的服务器对象列表。当ORB收到对某个服务器对象的引用请求后,就在自己维护的可用服务器对象列表中根据动态集中式负载分配算法找到可用对象,并将客户程序绑定到该对象的实例(在需要时将其激活)。 尽管CORBA提供了基本的负载均衡能力,但在某些特定的应用中仍显得性能不足。如前述的油藏描述问题,要求客户程序每变换一次参数,就新启动一个服务器进行分析,也即对每一个客户端请求实例,都必须有一个新的服务器对象来响应。而在CORBA中,对于客户端的同一个请求实例,都会固定地被绑定到同一个服务器对象。因此,需要对CORBA的基本负载均衡特性进行巧妙的应用以解决上述瓶颈问题。 方案一:采用多客户进程和多服务器进程(如10客户机和10服务器)的方式(见图1),使每个客户机都可以找到一个服务器进行计算。但这样带来的问题是,客户端为各个彼此间相互独立的进程,结果数据位于各进程的专有存储空间中,结果处理比较困难。 方案二:在客户端引入多线程技术,见图2。在客户机程序中建立线程组,组中的线程根据操作者进行计算的需要自动产生,并且都是同一个客户请求实例的副本。这样,每个副本实现了相同的请求实例却又相互独立,就可以激活不同的服务器完成相同功能的分析操作。由于线程共享内存单元,因此每个线程都可将计算结果存储在公用结果存储空间中,这就使得可以用客户端程序自动对计算结果进行平均处理。每当操作者修改了计算参数开始计算时,客户程序即向线程组中加入一个新的请求线程,通过ORB根据动态集中式负载分配算法找到一个空闲或负载最轻的服务器进行计算,并将返回的计算结果存入客户程序的公用结果存储区中。另外,在计算线程组之外还需要一个监控线程对计算线程组中各线程的状态进行轮询,以便当所有计算线程执行完毕并返回结果后触发结果处理操作。 经过方案二巧妙的技术处理,利用CORBA提供的基本负载均衡功能解决了特定应用的特殊要求所带来的瓶颈问题。 根据上面的思想,作者在某项目中应用了该技术。该分布式计算系统由一台微机和数台Sun工作站组成,CORBA客户端和ORB运行于微机上,在每个工作站上运行有计算程序—服务器程序对。整个处理过程耗时为第一个服务器启动到最后一个服务器启动的时间间隔加上单服务器执行时间。前者是调整参数时间,后者为真正的计算时间,且前者一般远小于后者。由此可以看出,应用该技术构建分布式计算系统,处理一个油藏描述问题所耗时间将约为原计算耗时的1/N(N为计算次数,整数),进行更复杂的处理时效率提高就尤为明显。 <淘宝热门商品:
 

218.00 元  

2件全国包快递!韩国SHEZ~SZ超值春秋装4件

 

288.00元  

【果然瘦身】(关于减肥药)瘦脸/瘦腿/小腰(专业指导你减肥)


来源:程序员网

小小豆叮

JAVA通过JNI调用本地C语言方法

JAVA以其跨平台的特性深受人们喜爱,而又正由于它的跨平台的目的,使得它和本地机器的各种内部联系变得很少,约束了它的功能。解决JAVA对本地操作的一种方法就是JNI。 JAVA通过JNI调用本地方法,而本地方法是以库文件的形式存放的(在WINDOWS平台上是DLL文件形式,在UNIX机器上是SO文件形式)。通过调用本地的库文件的内部方法,使JAVA可以实现和本地机器的紧密联系,调用系统级的各接口方法。 简单介绍及应用如下: 一、JAVA中所需要做的工作 在JAVA程序中,首先需要在类中声明所调用的库名称,如下: static { System.loadLibrary(“goodluck”); } 在这里,库的扩展名字可以不用写出来,究竟是DLL还是SO,由系统自己判断。 还需要对将要调用的方法做本地声明,关键字为native。并且只需要声明,而不需要具体实现。如下: public native static void set(int i); public native static int get(); 然后编译该JAVA程序文件,生成CLASS,再用JAVAH命令,JNI就会生成C/C++的头文件。 例如程序testdll.java,内容为: public class testdll { static { System.loadLibrary("goodluck"); } public native static int get(); public native static void set(int i); public static void main(String[] args) { testdll test = new testdll(); test.set(10); System.out.println(test.get()); } } 用javac testdll.java编译它,会生成testdll.class。 再用javah testdll,则会在当前目录下生成testdll.h文件,这个文件需要被C/C++程序调用来生成所需的库文件。 二、C/C++中所需要做的工作 对于已生成的.h头文件,C/C++所需要做的,就是把它的各个方法具体的实现。然后编译连接成库文件即可。再把库文件拷贝到JAVA程序的路径下面,就可以用JAVA调用C/C++所实现的功能了。 接上例子。我们先看一下testdll.h文件的内容: /* DO NOT EDIT THIS FILE - it is machine generated */ #include /* Header for class testdll */ #ifndef _Included_testdll #define _Included_testdll #ifdef __cplusplus extern "C" { #endif /* * Class: testdll * Method: get * Signature: ()I */ JNIEXPORT jint JNICALL Java_testdll_get (JNIEnv *, jclass); /* * Class: testdll * Method: set * Signature: (I)V */ JNIEXPORT void JNICALL Java_testdll_set (JNIEnv *, jclass, jint); #ifdef __cplusplus } #endif #endif 在具体实现的时候,我们只关心两个函数原型 JNIEXPORT jint JNICALL Java_testdll_get (JNIEnv *, jclass); 和 JNIEXPORT void JNICALL Java_testdll_set (JNIEnv *, jclass, jint); 这里JNIEXPORT和JNICALL都是JNI的关键字,表示此函数是要被JNI调用的。而jint是以JNI为中介使JAVA的int类型与本地的int沟通的一种类型,我们可以视而不见,就当做int使用。函数的名称是JAVA_再加上java程序的package路径再加函数名组成的。参数中,我们也只需要关心在JAVA程序中存在的参数,至于JNIEnv*和jclass我们一般没有必要去碰它。 好,下面我们用testdll.cpp文件具体实现这两个函数: #include "testdll.h" int i = 0; JNIEXPORT jint JNICALL Java_testdll_get (JNIEnv *, jclass) { return i; } JNIEXPORT void JNICALL Java_testdll_set (JNIEnv *, jclass, jint j) { i = j; } 编译连接成库文件,本例是在WINDOWS下做的,生成的是DLL文件。并且名称要与JAVA中需要调用的一致,这里就是goodluck.dll 把goodluck.dll拷贝到testdll.class的目录下,java testdll运行它,就可以观察到结果了。 <淘宝热门商品:
 

 

【上海商盟】高更食品极美滋新奥尔良系列烧烤腌料皇冠旗舰店

 

¥:59.00 

冉冉天使屋-外贸童装批发代理

冬季宝宝必备 加厚小老虎造型棉哈衣/可当包被 土黄色(0-1岁)


来源:程序员网

小小豆叮

Apusic应用服务器2.0 beta1发布

<淘宝热门商品:
 

0.90 元  

:①般般dē我 开【不】①般般的店

『四钻信誉』官方QB正规秒冲Q币,按元直充0.9元/QQ币

 

98.00 元 

莎莎调配速效去皱眼霜15g 淘宝眼霜销量冠军


来源:程序员网

小小豆叮

利用依赖值对象设计粗粒度BMP

利用依赖值对象设计粗粒度BMP 来自:www.theserverside.com By Floyd Marinescu, Senior Architect, The Middleware Company. Please email comments/suggestions to: floyd@middleware-company.com. 翻译photonman :tony_mao@hotmail.com 对性能和效率的关注就需要一个用BMP来构造粗粒度实体Bean集的标准途径,就象CMP做的那样(CMP使用其内支持的依赖对象)。 依赖对象为CMP实体Bean构建粗粒度实体Bean集提供了一个自动途径,但是EJB2.0规范并没有为BMP提供同样的支持。 构建粗粒度的Bean集是一个普遍使用的性能优化策略。这样会使得我们可以面向简单的Java类建模而不是实体Bean,同时减少了内部Bean的远程通信和应用在实体Bean上的事务处理。这些简单的Java类有典型的特点:依赖于父实体的生存周期、没有属于自己的标识和不能被客户端应用远程访问。对于CMP这些对象被称为依赖对象(dependent objects),在EJB2.0规范里面定义了一个标准的途径来定义CMP的依赖对象,把它们的复杂的持久化过程留给应用程序服务器。 不幸的是,BMP实体Bean的开发者无法享受依赖对象带来的便利,它们只是为CMP准备的。然而,BMP的开发者也需要创建粗粒度实体Bean集,因此: BMP开发人员就应该把商务数据建模成简单的Java类,我们叫作依赖值对象(Dependent Value Objects)。依赖值对象是被你的实体Bean创建和保存的。不象CMP的依赖对象,BMP开发者必须显式的处理依赖值对象的代码! 依赖值对象和值对象(Value Objects)类似,在于它们都是简单的Java类,并且都是可以通过网络来传输(这是一个优于CMP依赖对象的地方,CMP的依赖对象是客户端不可见的。)。但是又不同于值对象,依赖值对象是一些持久对象,实体Bean管理它们的生存周期,而值对象仅仅是一个需要传输的数据的批量化结果,而且得到这些数据以后,值对象就被丢弃了,并没有持久化。 一个实体Bean和其保存的依赖值对象的关系可以是1:1、1:N。例如:考虑一个履历(Resume)。一个Resume实体Bean一般只需要一个Address 依赖对象,然而可能对应于保存在一个Collection里面的多个Job Entry 对象,如图1: 图1: ResumeBean 类和依赖类Address、Job Entry的类图 实现BMP的依赖值对象不是一件轻松的事。一个好的实现在于:  依赖值对象和数据库中表的映射  不变的依赖值对象  依赖对象的Lazy loading  智能的生存期管理?(更新缓冲直到ejbStore, 如:仅仅保存新的或者是被修改过的依赖对象)  从商务逻辑中分离出持久逻辑 实现依赖值对象的持久化最简单的途径:序列化这些依赖值对象到其父实体Bean所对应的表的一个BLOB字段里。如果是处理一个依赖值对象的集合,这个整个集合就被序列化到这个字段里面。一个改进的选择是:持久你的依赖值对象到一个单独的表,使用JDBC以一个字段一个属性的方式映射你的依赖对象。保持以这种方式持久,可以使得你能通过sql来访问你的依赖值对象,并且你可以直接在数据库的层次来报告和维护你的依赖值对象(如果是个BLOB,你将不能做这些事)。对于我们的例子Resume,Resume实体映射到一个数据库里resume的表,而我们的Address依赖值对象映射到address表,Job Entry映射到jobentries表,如图2所示。因为我们的address和job entries 是依赖值对象,它们没有除了Resume实体的标识以外的标识,这样就不需要它们自己的主键(Primary Key),因为它们被resumeID唯一标识。 图2:EJB 和依赖对象的DB 映射 不可改变 依赖值对象应当是不可改变的(immutable),也就是说它们没有setter方法。在CMP概念里,依赖对象是对客户端不可见的,它们只能在实体Bean内部被访问。这样处理的一个好处就是对于依赖对象的更新只是局限在实体Bean的商务方法(封装)。对于BMP,我们没有碰到这样的限制,因为依赖值对象是常规的Java类。为了达到CMP一样的封装但是又不失可以在网络上传输的优势,它们就应当是被定义成不可改变的。这就保证客户端对依赖值对象的修改不会马上反应到服务器端,也就是说强制客户端只有通过实体Bean的远程接口才能对依赖值对象的各种操作。 Lazy Loading 是一个增强性能的策略,它允许依赖值对象在需要的时候被加载,而不是预加载。它防止了在ejbCreate()方法里面加载所有实体Bean的依赖值对象的无用消耗,特别是在某个客户端并不对这个依赖对象感兴趣时。 Lazy loading是易于实现的。每一个依赖值对象或者它们的集合,都应当有这样的一个getter方法:  检查这个内部的依赖值对象是不是已经加载过(是null)。  如果没有加载那么调用数据库加载对象。  把得到的依赖值对象传给调用者。 一旦从数据库里得到依赖值对象(或者它的集合),那么可以在实体Bean里保存起来,作为一个缓冲数据,用于下一次的调用,就象在Resume实体Bean中的方法getAddress()和getJobs()(参见本模式下面的可以下载的例子)。 智能生存期管理 在BMP的环境下,程序员要负责智能生存期管理的工作。不幸的是这个工作很具有挑战性,特别是在处理依赖值对象的集合时。必须写大量的生存期管理和数据的同步逻辑来跟踪依赖值对象的状态,当它们被创建、更新和删除时。好的BMP实现仅仅当依赖值对象被修改、创建或者删除时更新数据库。它也允许在一个事务环境里对同一个依赖值对象的多操作(更新、删除等等),并且当这个数据库事务结束时只同步这个实体Bean的依赖值对象的最后状态。 从商务逻辑中分离持久逻辑 许多的BMP开发者由于过分关注依赖值对象复杂的生存期管理,他们会选择通过给依赖值对象增加主键(primary key)或脏标识(dirty flags),把持久逻辑混合在商务逻辑里,甚至为了跟踪依赖值对象的生存周期而使得商务方法交织在一起。为了使得在BMP中实现依赖值对象和在CMP中一样简便,每一个开发者都不应该给依赖值对象加入额外的特殊字段,也不应该把持久逻辑和商务逻辑混合在一起。 那么,一个BMP开发者要怎么做才能轻松而聪明的开发依赖值对象的智能生存期管理而保持持久逻辑和商务逻辑相分离呢?答案就是抽象这些细节到一个为了跟踪依赖值对象的生存期而建立的特殊的集合类中。图3展示了一个DepedentValueSet类,Java 2 Set 集合类的一个特殊实现。在实现平常的Set的操作(包括add、remove等等)的同时,这个集合加了几个新的方法包括一个把两个依赖值对象作为参数的update(oldObject,newObject)方法。由于依赖值对象(象CMP的依赖对象)是没有任何的自己的标识的(没有primary key),我们就要求传递原始的对象,这样我们的集合类就知道哪个对象要被更新。 图3:DependentValueSet类 使用这个DependentValueSet就使得BMP的开发者可以把持久逻辑从商务逻辑中分理出来,因为商务方法要做的仅仅是和一个普通的Set的接口和额外的update接口交互。而依赖值对象也可以保持其清晰而简洁,它们自己不需要额外的特殊字段来跟踪它们的状态,就象DependentValueSet处理的那样,所有这些都是透明而显然的。 我们的DependentValueSet实现允许当我们依赖值对象在内部被创建、删除或者修改时,跟踪其生存周期。特别当一个用户在一个事务环境里面对这个依赖值对象执行了多重操作并且同步了这个依赖值对象的最后状态,在ejbStore()只有一次更新。例如:对同一个依赖值对象可以做更新操作多次,但是在ejbStore()方法里面,数据库只需要一次更新操作。 为了支持数据库的同步,我们的DependentValueSet加了5个额外的方法: • addObjectFromDatabase(Object) • getObjectsToInsert() • getObjectsToDelete() • getObjectsToUpdate() • databaseHasBeenUpdated() addObjectFromDatabase是当依赖值对象初次从数据库里取得时调用。它允许跟踪这个对象的数据库的初始状态。getObjectToXXX方法允许BMP开发者查询DependentValueSet来得到哪一个对象应该被插入、删除或更新,同时在ejbStore()方法里写这个依赖值对象的特殊的SQL代码来处理这些更新。一旦同步完成,DepedentValueSet应该唤醒(数据库已被更新),这样它就可以清楚自己的状态以供下一个事务之用。 在我们的Resume例子里面,我们保存了工作的集合在DependentValueSet。实体Bean公开这个job entries的创建、读取、更新和删除操作。每一个都是分派给DependentValueSet的jobentries方法,这个方法处理所有对resume jobs的生存周期的跟踪。在事务结束的时候(ejbStore()),我们查询DependentValueSet来检测那个job entries被创建、删除或更新,根据结果我们执行相应的SQL语句,更新数据库。 每一个Resume仅仅包含一个Address依赖值对象,因此我们不需要DependentValueSet的高级服务。相反我们可以自己处理get和set这个Address对象,同时简单地保持一个isAddressModified标识,这样ejbStore()将会知道这个Address是否在事务环境中被修改,如是那么保存它。 译者注: 本文给出了在实体Bean设计时缓和性能、负载、效率和扩展性的策略。分离持久逻辑和商务逻辑使得代码易于理解和扩充。前几天有网友讨论实体Bean的设计,我想可以从中找一些思路,特此翻译成中文,希望对大家的EJB设计有所帮助。由于本人水平有限,其中错误不正之出不在少数,在此付上原文,以便对照,恳请读者斧正。 ――-photonman 英文原文: Coarse Grained BMP beans with Dependent Value Objects By Floyd Marinescu, Senior Architect, The Middleware Company. Please email comments/suggestions to: floyd@middleware-company.com. Performance and efficiency concerns require a standard way to build coarse-grained entity beans using BMP as well as CMP. Dependent objects provide an automatic way to build coarse-grained entity beans for CMP entity beans, but the EJB 2.0 specification doesn’t provide an equivalent mechanism for BMP entity beans. Building your entity beans to be coarse-grained is a common performance optimization. It allows modeling the business objects with plain java classes rather than as entity beans, reducing the inter-remote object communication and transactional overhead associated with entity beans.?These plain classes typically have a life cycle dependent on a parent entity bean, do not have a distinct identity of their own and do not need to be referenced remotely by a client. For CMP, these objects are called dependent objects, and EJB 2.0 defines a standard way to define CMP dependent objects, leaving the complex task of persisting them to the underlying application server. Unfortunately, BMP entity bean developers cannot leverage dependent objects, they are a CMP construct only. However, BMP developers should still be able to create coarse-grained entity beans, Therefore: BMP developers should model dependent business data in plain java classes called Dependent Value Objects.?Dependent Value Objects are stored inside your entity beans and are created, modified and removed by your entity beans. Unlike dependent objects with CMP, BMP developers must explicitly write the persistence code of dependent value objects. Dependent Value Objects are similar to Value Objects in that they are plain java classes and are transportable over the network (this is one advantage over CMP dependent objects, which cannot be accessed by clients). Unlike Value Objects, Dependent Value Objects are persistent objects whose life cycle is managed by an entity bean, whereas Value Objects only exist to transport data across the network in bulk, and are typically discarded once data has been read. An entity bean can store dependent value objects in a one to one, or one to many fashion.?For example, consider a Resume. A Resume entity bean would only require one Address dependent value object, whereas it would require multiple Job Entry objects, which could be stored in a Collection inside the Resume entity bean, as in figure 1. Figure 1: ResumeBean class diagram with Address and Job Entry Dependents Implementing dependent value objects with BMP is not trivial. A good implementation will feature: • Dependent value objects that map to tables in a database • Immutable dependent value objects • Lazy loading of dependent value objects • Intelligent lifecycle management?(caching updates until ejbStore, only storing new or modified dependent value objects, etc) • Partitioning of persistence logic from business logic One of the easiest ways to persist dependent value objects is to simply serialize them to a SQL BLOB column in the table which your entity bean maps to. If dealing with a collection of dependent value objects, the whole collection could be serialized into this column. A better alternative is to persist your dependent value objects to separate tables, using JDBC to map your objects in an attribute-per-column manner. Persisting your dependent value objects in this manner will allow them to be accessible to sql searches and allow you to perform reporting and maintenance directly on the database (you can’t do this if they are stored as blobs). From our Resume example, our Resume entity bean maps to a resumes table in the database, whereas our Address dependent value object maps to an addresses table and our Job Entries map to a?jobentries table, as in figure 2. Since our addresses and job entries are dependent value objects, they do not have their own identity outside of their parent Resume entity bean, and thus they do not have their own primary key, instead they are identified by a resumeID column in the addresses and job entries table. Figure 2: EJB and dependent object DB mapping Dependent Value Object should be made immutable, that is, they should have no set methods.?In CMP, dependent objects cannot be passed to a client, they can only be accessed internally by an entity bean. One advantage to this restriction is that it ensures that any updating of data in an entity bean is done through the entity bean’s own business methods (encapsulation).?In BMP, we are not faced with this restriction since dependent value objects are just regular java classes. In order to achieve the same benefit in BMP but still have the flexibility of passing our dependent value objects to clients, dependent value objects should be made immutable. This will ensure that the client doesn’t make changes to the value object assuming that his changes will be instantly reflected on the server, thus forcing the client to perform all changes through the entity beans remote interface. Lazy Loading is a performance enhancement that allows dependent value objects to be loaded on demand. It avoids the wasteful practice of loading up all of an entity beans dependent value objects inside ejbCreate(), particularly if a client isn’t interested in the dependent data. Lazy Loading is easy to implement. Each of your dependent value objects or collections can have get methods which: • Check to see if the internal dependent value object or collection is has been loaded (is null). • Calls the database and loads up the requested dependent data if not previously loaded • Passes the requested dependent value object (or collection) to the caller. Once the dependent value object (or collection) has been read from the database, it can be cached inside the entity bean for future calls, as in our getAddress() and getJobs() in our Resume Bean (see downloadable example source at bottom of pattern). In a BMP scenario, intelligent life cycle management is the programmers responsibility. Unfortunately, this is not trivial, particularly when dealing with a collection of dependent objects. A lot of life cycle management and database synchronization logic must be written to track dependent value objects as they are created, updated, and deleted.?A good BMP implementation will only update the database with dependent objects that have been modified, created or deleted.?It will also allow multiple operations (update, delete, etc) on dependent objects within one transaction and only synchronize the final state of an entity bean’s dependent objects with the database at transaction completion (in ejbStore). Partitioning of persistence logic from business logic. Given the complexities of life cycle management of dependent value objects, many BMP developers choose to mix their persistence logic with their business logic by adding primary keys or dirty flags to dependent value objects, even interlacing their business logic with code necessary to track the life cycle of dependent value objects. To make programming with dependent value objects in BMP as easy as it in CMP, a developer should not add any special fields to his dependent value objects, nor should persistence logic be mixed in with business logic. So how can a BMP developer achieve intelligent dependent value object lifecycle management and keep persistence logic separate from business logic? The answer is to abstract these details into a special collection class designed to track the lifecycle of dependent value objects that it is storing.?Figure 3 illustrates a DependentValueSet, a special implementation of the Java 2 Set Collection. Along with supporting the normal operations of a Set (including add, remove, etc), the collection adds several new methods including an update(oldObject, newObject) method that takes two dependent value objects as a parameters, the original object and the newly updated one.?Since dependent value objects (like CMP dependent objects) do not have any identity of their own (no primary key), we require that the original object be passed as a parameter so that our Set will know which object to replace. Figure 3: The DependentValueSet Class Using the DependentValueSet allows CMP developers to achieve separation of persistence logic from business logic because business methods need only interact with the normal operations of the Set interface and the extra update method. Dependent Value Objects are also kept clean; they do not need any special attributes added to track their state, as the DependentValueSet handles all of that transparently. Our DependentValueSet implementation allows for intelligent lifecycle management by tracking which of our dependent objects were created, deleted or modified internally. This is extremely powerful as it allows the user to perform multiple operations on dependent value objects within one transaction, and synchronize the final state of our dependent value objects just once in ejbStore(). For example, the same dependent value object can be updated multiple times, but in ejbStore(), only one database update needs to be performed. To support database synchronization, our DependentValueSet adds 5 extra methods: • addObjectFromDatabase(Object) • getObjectsToInsert() • getObjectsToDelete() • getObjectsToUpdate() • databaseHasBeenUpdated() The addObjectFromDatabase method is meant to be called when dependent value objects are initially loaded from the database. It allows the DependentValueSet to track the objects that were initially in the database. The getObjectToXXX methods allow a BMP developer to query the DependentValueSet to find out which objects should be inserted, deleted, or updated, and write the dependent value object specific SQL code to handle these updates in ejbStore(). Once synchronization is complete, the DependentValueSet should be notified (databaseHasBeenUpdated ) so that it can clear itself up for the next transaction. From our Resume example, we store our collection of job entries in a DependentValueSet. The entity beans remote interface exposes create, read, update, and remove (CRUD) operations for job entries, each of which delegate to methods on the DependentValueSet called jobentries, which handles all the life cycle tracking of the resumes jobs. At the end of the transaction (in ejbStore() ), we query our DependentValueSet to determine which job entries have been created, removed, or updated, and execute the appropriate SQL accordingly. Each Resume only requires one Address dependent value object, thus we don’t need the advanced services of our DependetValueSet. Instead, we can manually get and set the object, and simply keep around an isAddresssModifed flag so that ejbStore() will know if our Address has been set in this transaction, and store it in the database if so. <淘宝热门商品:
 

 

【广州商盟】意外金喜服装◎抵制暴利低价有好货◎收藏小店有惊喜

 

¥:338.00 

【澳钻/Swarovski/手机钻/美甲钻/婚沙礼服钻】专卖店

【五钻信誉】Swarovski々豪华水晶甲々1200颗338元[包快递]


来源:程序员网

小小豆叮

构建企业级应用的六大误区

Six Common Enterprise Programming Mistakes by Brett McLaughlin, author of Building Java Enterprise Applications Vol. I: Architecture 04/03/2002 Instead of giving you tips to use in your programming (at least directly), I want to look at some common mistakes made in enterprise programming. And instead of focusing on what to do, I want to look at what you should not do. Most programmers take books like mine and add in the good things, but they leave their mistakes in the very same programs! So I'll touch on several common errors I see in enterprise programming, and then briefly mention how to avoid those mistakes. 1. It doesn't matter what data store type you use. One of the first steps in designing an application is to decide on the data store. It used to be that every application was based upon a database, and this was simply not an issue. However, there has recently been an upsurge in additional options: you can now use relational databases, XML databases, object databases, directory servers, and more. As a result, many companies have begun to interchange these different data stores, often without any real thought. If a directory server is cheaper than a database, it is used to replace the database. XML databases are put in place because they are "sexy" and satisfy "technology lust." However, the trend to use any data store for any case is simply absurd; your performance will began to degrade, your code will become overly complex, and you'll have no idea why. Each data store has a specific purpose. For example, directory servers are optimized for frequent reads, with few writes. Authentication and searching for names and addresses is a perfect usage of a directory server. However, if you start to add data programmatically to a directory server often, you’ll see a degradation in performance. A database is better in this case. The same sort of choices are important when determining what kind of database to use. For example, using an XML database in an application that never pulls XML directly out of that database is silly. You're choosing a technology (XML), and then never using that technology. In my new book, I detail these exact choices. (Yes, it's more than just a book about Java.) In fact, you'll learn how to integrate databases and directory servers into the same application, and even how to transfer data back and forth between them. 2. Vendor-specific programming speeds up programming tasks. Far too often, programmers take shortcuts to write code faster. However, more often than not, these "shortcuts" turn into long-term pitfalls. No matter how much time this may save a programmer up front, it will always end up taking more time in the long run to undo and redo correctly. Let me give you an example. Take the issue of working with Enterprise JavaBeans (EJB) and database tables. A common issue is inserting a number into the ID field of a table. Because Oracle uses sequences to allow this, MySQL uses an auto-increment field, and other tables may not provide any numbering facility at all. What I see, time and time again, is code in an EJB that directly accesses that Oracle sequence, or MySQL incremented field, or any other database. In other words, these EJBs would not work on any database but the one they were coded to; in fact, they often won't work with different versions of the same vendor's database. The result is a non-portable, short-lived piece of code that won't be able to keep up with the changes of your company. Instead of this approach, it is possible to devise a method where your own beans handle this numbering. By putting the code into your beans, and removing it from the vendor-domain, you suddenly are back to vendor-neutrality, flexibility, and even (in many cases) better performance. If you check out my book, I'll give you the exact code to handle this specific case, and show you in detail how to avoid these vendor-specific problems. 3. I need an editor or tool to write my Enterprise JavaBeans. I'm often asked about the tools that I use in my EJBs. Specifically, people want to know what I use to generate my remote interface, home interface, and implementation-class source code. The idea is that there is so much repeated code in these components that you have to have a tool in order to make things easier. The mistake creeps in when you go in and modify these skeletons, and miss a spot here, or accidentally foul up a method signature there. The result is code that fails compilation and is often hard to debug. Now maybe it's just that I cut my teeth on Java using vi and notepad, but I'm content with Ctrl+C and Ctrl+V, and 'yy', 'dd', and 'p'. Cutting and pasting in these text editors has kept me much better off than any editor or tool ever has. It also generally results in me understanding my code better, and knowing exactly where everything in my code is. I'm not saying that you shouldn't use an editor or a tool (I often use jEdit.); however, as soon as you depend on those tools, you're in trouble. Take a week to code in nothing but a text editor, and you'll be amazed at how reacquainted you manage to get with your code. Of course, my book assumes no such tools, and it walks you through the exact process that results in efficient, logical coding of beans, as well as other components in your application. 4. I've got to include JMS, XML, JAXP, and more in every application. I realize that if you’ve been reading my books and articles for very long, you’re probably tired of this sort of thing. I'm constantly harping on programmers, insisting that they only use what they need in their programs. However, until I see people get over their technology-lust, I'll keep hollering about this one. The basic mistake I'm referring to is the thinking that everything in J2EE must be used in a J2EE application. If that application doesn't use EJBs, JMS, JMX, XML, and every other acronym on the package of your application server, you think you're somehow wasting money. Nothing could be further from the truth, though. In fact, in my latest book, I had to almost force in a chapter on JMS (the Java Message Service). This isn't because JMS isn't important; it's simply that the application I was writing for the book didn't really need JMS that much. I have written several applications that do use JMS, and I was able to come up with a pretty good use-case for JMS in the book. However, that situation is a perfect illustration of the issue: sometimes you just don't need the whole kitchen sink. In any case, for about the 50th time, you should only use what you need. If all that is required is a couple of servlets and some JDBC code, then stick with that; don't add the complexity of EJBs if you don't need it. If you need EJBs, but message-driven beans are beyond the scope of your application, don't worry about it. In the long run, you'll appreciate the resulting simplicity of your application. 5. Stateful beans make programming more object-oriented. This is a common one, and usually an easy one to correct. The basic mistake involves the way that methods are called. For example, here's a few methods that you might find in a stateful session bean's remote interface: public User create(String username); public Address getAddress(); public List getAccounts(); public boolean deleteAccount(Account account); The thinking is that you need to make this a stateful session bean so that you can pass in the username only one time (in the create() method). So your method calls would look like this: User user = userHome.create(username); Address address = user.getAddress(); List accounts = user.getAccounts(); This is more object-oriented than using a stateful bean, which has methods more like this: public User create(); public Address getAddress(String username); public List getAccounts(String username); public boolean deleteAccount(String username, Account account); The result is that the same code block would look like this: User user = userHome.create(); Address address = user.getAddress(username); List accounts = user.getAccounts(username); Wow! It's obvious that this is so much harder to understand and work with. (OK, that was a bit sarcastic; print is such a hard medium to get clever in.) As you can see, this may not be quite as OO (object-oriented). However, you'll find that changing to the stateless approach (shown second) results in a speed up to the tune of 10 times or sometimes even 100 times faster (depending on the application server). So for this rather small sacrifice in OO coding results in your code speeding up dramatically. One more mistake dealt with and out of the way. 6. I don't need anyone telling me what to do in my programming. Ah, yes. We've all been there, right? I remember my first few years of programming when I knew that I was going to always innovate, always create, never copy, and never need any help. Of course, I later found out that most of my clever "innovations" were poor solutions to well-understood problems, many with established "best-case" solutions. It's absurd to be so egotistical as to refuse to accept help when it's offered. Is this a shameless plug for my book? No, not really. I'd advise you to go out and get anything you can find on the subjects you are working in. Heck, I have nearly as many non-O'Reilly technical books as I do O'Reilly books, and I use my whole library all the time. I'd also recommend you get involved in the open source community. You'll learn more than you could ever imagine. The bottom line is that there are a lot of really bright people out there, and I'd suggest you suck all the knowledge from these folks that you can. As soon as you decide that you don't need anyone else's help, you'll certainly begin to make more mistakes than ever. Well, there are six common problems I see cropping up time and time again. You may see one or two in this list that you yourself have ascribed to. Don't feel embarrassed; I've been guilty of all of these at one time or another, but I got over it. Just take them as spurs to make you a better programmer. I hope you enjoy the new book, and I look forward to hearing what you think. See you online! <淘宝热门商品:
 

鲜花速递/蛋糕配送/园艺花艺 

瑞锦记锦缎喜糖袋〓婚礼特制●上等材质●流行韩

 

¥:338.00 

【澳钻/Swarovski/手机钻/美甲钻/婚沙礼服钻】专卖店

【五钻信誉】Swarovski々豪华水晶甲々1200颗338元[包快递]


来源:程序员网

小小豆叮

軟體創新設計:創新思考的幾項迷思(二)

我們在開發系統的時候經常會陷入一個迷思,不知如何打入市場,為了創新而創新,結果經常走入死胡同,以下幾點提供大家在創新思考的時候應該要注意的事情。 創新就是使用新技術嗎? 如果以PC的硬體發展的趨勢,加上軟體技術的日新月異,很多人使用快速的軟體開發,導致所有的程式設計都想學新的技術,但是我們一定要回頭想一想,新技術有降低成本嗎?新技術對未來維護有方便性?新技術可以符合產品的需求?新技術對於軟硬體支援有相容性?新技術有制定標準規格? 如果這些答案的評估都是正向的,當然可以使用新技術,但是創新的要點並不是使用新技術,只是用了新技術可以比較容易達成創新的目的,所以即使通過了上面的檢驗,我們還是要先制定產品創新的規格才能繼續評估,是否使用新技術。 創新就是開發新功能嗎? 有人以為不斷地提供新的功能給客戶,就是創新。其實大大的不是,創新應該還是要符合客戶的需求,如果這個需求只是為了改版而改版,根本沒有符合客戶的最大使用功能來修改的話,可能不要改來的好,因為改了版本還要經過一段時間的陣痛期。 而有時候一項好的創新服務可能只是改了功能表的位置,按鈕的熱鍵設定,或者產品的重新包裝,甚至只是操作手冊線上服務的字眼,或者只是行銷計劃重新組合而已,所以,新功能可以是創新的一部份,但是並不是大部分。 創新就是與別人不同嗎? 我們經常為了與競爭對手做一些區別,會想出不同的操作方式,或是畫面的設計排列重整,有些時候是非常不好的,例如當大家已經熟悉跑馬燈是由右至左跑的時候,如果你跑一個由左至右的跑馬燈,一定沒有一個人會習慣的。 如果一個系統已經沒有創新的空間的時候,千萬不要在變花樣去想與別人不一樣,可以在系統的效能,系統的架構去想創新,抄襲別人的東西雖然想起來不好,但是如果要改變所有人的操作習慣,可能沒有人要使用你的產品的。 而與別人不同的地方應該是讓人更方便、更迅速獲得想要的內容、或是更能壓低成本的創新。 <淘宝热门商品:
 

215.00 元  

08秋冬新款 D&G 优质面料修

 

120.00 元  

上万淘友使用推荐、修复红血丝、敏感、痘印(全国总代)


来源:程序员网

小小豆叮

軟體創新設計:創新思考的幾項方法(一)

點子在你需要的時候就會有,不要想破頭。 我們經常聽人家說想到一個好點子是需要有第六感,或是有神來之筆,所以在思考的時候,千萬不能急躁,寫程式或是想事情的時候想不出解答,可以先放在一邊,搞不好在日常生活中,例如洗澡的時候、散步的時候、逛菜市場的時候,都有可能想到解答。 不過創新的點子是一定要經過耕耘的,並不是一蹴可及的,像一般我們熟知的大企業,時常注重創新的公司,無可避免地必須要有特別的部門,或是主管明確地犧牲效率或是其他的資源,以換取員工能夠誕生新的構想,他們不一定看到每一步的作業,不過必須尊重或是支持創新的成本。 阿基米德在洗澡地時候發現了水的浮力,而牛頓在樹下打瞌睡的時候發現了地心引力,為什麼這些故事都是發生在國外? 所有新的構想都是可以發揮的好構想。 並不是所有的創新構想一開始都是可以執行成功的,都是經過琢磨而成為可執行的點子,通常一個新構想被提出來的時候,聽起來都爛的不得了,可以直接丟到垃圾桶去,但是簡單的修飾之後,或是利用創意組合的方式,搭配另一個舊的構想,有時候會成為不得了的結果。 例如一個公司的核心產品,總會想要自己來做業務行銷的工作,但是如果是一個比較過氣的核心技術,有時候如果自己在繼續開發,也自己來賣的話,有時候因為包袱比較大,可能成本比較大,所以有些公司會把這一類的技術賣給競爭對手,反而是減低成本,而這種創新構想當然風險很大,但是也是一個新的構想,我們不能就此鄙棄這種點子。 客戶知道他們要什麼,他們有很多好的構想。 對於技術研發的工程師來講,去跟客戶拿點子簡直是天方夜譚,因為客戶會先指出你原先的系統產品,有哪些錯誤要修正,哪些不符合需求,而這種修改曠日費時,依照這種客戶訪談的前進模式,業績量雖不至於衰退,但也不會有大的成長。 所以跟客戶溝通,做問券調查,用緊密的篩選客戶真正的需求,這種方式一定不能想出好的點子,跟客戶可以用非傳統的模式,例如微軟就是偷偷地用攝影機紀錄客戶接收到新產品的安裝及操作的模式,而一般的飲料上市前的行銷會議,就是把個人的感覺辦的像經驗分享一般。 這些方法並非每次可以重複使用的,要取的好構想好點子,就要用不同的方法在準客戶中取的創新的構想。 <淘宝热门商品:
 

138.00 元 

专业定做925纯银 字母项链 刻字项链 名字项链

 

88.00 元  

【广州商盟】外贸男装、男鞋工厂直接供货批发零售

〖亿贝特价〗外贸原单Versace范思哲多LOGO特色羊毛衫、毛衣V灰紫


来源:程序员网

小小豆叮

J2EE 组件开发:消息驱动的EJB

一、概述 消息服务是一种在分布式应用之间提供消息传递服务的软件,具有可靠、异步、宽松结 合、语言中立、平台中立的特点,而且通常是可配置的。它的实现原理是:对发送者和 接收者之间传递的消息进行封装,并在分布式消息客户程序结合的位置加上一个软件处 理层。消息服务为消息的客户程序提供了一个接口,这个接口隔离了底层的消息服务, 使得各种不同的客户程序能够通过一个友好的编程接口方便地通信。 Java消息服务(Java Message Service,JMS)是一个Java API,它定义了消息的客户程 序如何以一种标准化的形式与底层的消息服务提供者交互。JMS提供了一种接口,底层消 息服务提供者通过该接口向客户程序提供JMS消息服务。JMS提供了点对点消息模式(Po int-to-Point)和发布-订阅消息模式(Publish-Subscribe)。点对点消息模式通过一 个消息队列实现,消息的生产者向队列写入消息,消息的消费者从队列提取消息。发布 -订阅消息模式通过一个话题(Topic)节点构成的层次结构实现,消息的生产者向这个 层次结构发布消息,消息的消费者向这个结构订阅消息。 点对点消息模式具有如下特点: 每一个消息只有一个消费者。 消息的接收者和发送者之间不存在时间上的依赖关系。不论发送者发送消息时接收者是 否在运行,接收者都可以提取信息。 接收者对于成功处理的消息给出回执。 发布-订阅消息模式具有如下特点: 每一个消息可以有多个消费者。 向某个话题订阅的客户程序只能收到那些在它订阅之后发布的消息。为了接收到消息, 订阅者必须保持活动状态。因此,发布者和订阅者之间存在时间上的依赖关系。 JMS API在一定程度上放宽了对这种依赖关系的要求,允许创建持久性订阅(Durable S ubscription)。有了持久性订阅,当订阅者不活动时发送的消息也能接收到。 EJB 2.0规范定义了一种新的EJB类型,即消息驱动的EJB(Message-Driven EJB,简称M DB),它能够以EJB的形式实现JMS消息的接收者。消息驱动的EJB实现一组新的接口,这 组接口使得EJB能够异步地接收和处理JMS消息生产者发送到队列或话题的消息。EJB客户 程序的构造方式与普通JMS消息生产者的构造方式完全一样,也就是说,JMS消息生产者 不必知道消息的消费者是一个EJB。 相对于会话Bean和实体Bean而言,消息驱动的Bean最大的特点是客户程序不通过接口访 问Bean。与会话Bean和实体Bean不同,消息驱动的Bean只有一个Bean类。从某些方面看 ,消息驱动的Bean类似于无状态会话Bean: 消息驱动的Bean不为特定的客户保留数据或对话状态。 一个消息驱动Bean的所有的实例都是等价的,这使得容器能够把消息指派给任意一个消 息驱动Bean的实例。容器能够建立消息驱动Bean的缓冲池,实现消息的并发处理。 一个消息驱动的Bean能够处理来自多个客户程序的消息。 消息驱动Bean的实例变量可以在处理客户消息期间包含一些状态信息,例如JMS连接、打 开的数据库连接,或者是对EJB对象的引用。当一个消息到达,容器调用消息驱动Bean的 onMessage()方法处理消息。onMessage()方法通常把消息定型(cast)成为五种JMS消息 类型之一,然后按照应用的业务逻辑的要求处理消息。 传递给消息驱动Bean的消息可能处于一个事务之内,这时,onMessage()方法内的所有操 作都属于该事务的一部分。如果消息处理结果被回退,则系统将再次投递该消息。 哪些时候应该使用消息驱动的Bean呢?会话Bean和实体Bean能够发送JMS消息,能够同步 接收消息,但不能异步接收。一些时候,为防止过多地占用服务器资源,在服务器端的 组件中,我们想要避免阻塞,这时,我们可以用消息驱动的Bean异步接收消息。 二、MDB体系结构 图一描述了消息驱动的Bean组件的基本体系结构。 在图一中,位于顶端的是javax.ejb.EnterpriseBean接口,它是所有EJB的基础接口。E nterpriseBean接口派生出了javax.ejb.MessageDrivenBean接口,所有消息驱动的EJB类 必须实现javax.ejb.MessageDrivenBean接口。此外,消息驱动的Bean必须实现javax.j ms.MessageListener接口。公用的、非最终的、非抽象的消息驱动的EJB,比如图一显示 的MyMessageDrivenEJBean,必须同时实现MessageListener接口和MessageDrivenBean接 口。消息驱动的EJB与其他类型的EJB不同,它们不把业务方法导出给客户程序,它们关 心的只是遵从EJB容器的接口要求。由于这个原因,消息驱动的Bean必须有一个不需要参 数的公用构造方法(ejbCreate()方法),而且不应该实现finalize()方法。 2.1 MDB接口 在消息驱动的Bean中,setMessageDrivenContext()方法用来把一个MessageDrivenCont ext的对象实例传递给EJB,它是MessageDrivenBean接口定义中容器调用的第一个方法。 MessageDrivenContext对象封装了一个EJB消息驱动容器上下文的接口,支持消息驱动的 EJB实例访问容器提供的运行时消息驱动上下文 对于消息驱动的EJB来说,关键之一是要实现一个没有参数的ejbCreate()方法。当EJB容 器准备创建消息驱动EJB的实例时,它将调用这个方法。容器之所以决定创建某个EJB的 实例,可能是因为它要构造一个Bean实例的缓冲池,也可能是因为它接收到了客户的请 求。这个ejbCreate()方法和其他Bean上的EJB构造方法类似,属于EJB实现的一种特殊的 构造函数或初始化方法。 当EJB容器准备不让Bean实例继续处理客户程序的请求时,它就会调用消息驱动Bean的e jbRemove()方法。何时在消息驱动的Bean上调用ejbRemove()方法由EJB容器单独决定, 不受EJB客户程序的任何约束。应当注意的是,容器并不保证一定调用ejbRemove()方法 。在正常操作时,容器会调用ejbRemove()方法;但是,当消息驱动的Bean向容器抛出了 系统异常时,不能保证ejbRemove()方法一定会被调用。由于这个原因,Bean开发者必须 按时检查和清除Bean分配的所有资源。 对于Bean开发者来说,最重要的任务也许是实现onMessage()方法。当一个异步消息必须 由Bean实例处理时,容器将调用onMessage()方法。onMessage()方法的参数是一个普通 的JMS javax.jms.Message的实例,消息驱动的EJB实例从这个Message的实例提取待处理 的数据完成消息处理。 2.2 JMS消息接口 那么,在onMessage()方法调用传入的 JMS消息中,消息驱动的Bean如何提取信息,可以 提取哪些信息呢?图二描述了基本JMS消息类型的核心接口和概念。在一个以JMS为基础 的消息系统中,Message接口是在系统中传递的所有消息的最基本的接口(或称之为根接 口,Root Interface)。Destination接口描述了消息传递的一个终端;类似地,由于消 息有一个传递模式,所以图二还显示了Message接口与DeliveryMode接口的概念上的关系 。 JMS消息的头信息可以通过一组标准的方法设置或提取,这组标准方法的名字为getJMSX XX()或setJMSXXX()形式(下面我们分别称之为get方法和set方法),其中XXX是消息头 信息中的属性名字,例如getJMSDeliveryMode()方法。在Message接口中,通过get方法 和set方法操作的标准头信息属性包括:唯一的消息ID,时标(Timestamp),答复和目 标地址,消息传递模式,消息类型,以及消息的优先级。 在JMS消息中,JMS容器提供者特有的属性可以通过getXXXProperty()方法提取,或通过 setXXXProperty()方法设置,其中XXX表示属性的类型,例如byte getByteProperty(ja va.lang.String name)。每一个属性有一个通过String对象指定的名字和相应的值。名 字以JMSX前缀开头的属性作为标准JMS属性保留。 与消息正文数据(或称之为消息体,与消息头相对而言)的五种类型对应,五种消息类 型扩展了Message接口,如图三所示。Byte数据由BytesMessage封装,Serializable对象 由ObjectMessage封装,String消息由TextMessage封装,键-值对由MapMessage封装,I /O流由StreamMessage封装。 这些派生消息类型上的方法为特定类型的消息正文定义了get和set操作,而在Message基 础接口内,有一个通用的clearBody()方法,这个方法清除消息的正文,并把它置入只写 模式。clearBody()方法只清除消息正文,不清除消息头或属性。如果消息正文是只读的 ,调用该消息后,消息正文的状态将和新消息的空白正文状态一样。 2.3 MDB客户程序接口 消息驱动Bean的客户程序并不知道接收端实际处理消息的将是一个EJB。事实上,消息驱 动Bean的客户程序的构造方法与普通JMS客户程序的构造方法完全一样。 JMS的核心体系如图四所示。从图中我们可以看出,JMS ConnectionFactory(连接工厂 )初始上下文通过Java名称和目录接口(Java Naming and Directory Interface,JND I)创建。随后,连接工厂将用来创建与JMS服务提供者的连接。有了JMS连接,我们就可 以获得创建消息生产者和消息消费者的会话(Session)。实际上,消息驱动Bean的客户 程序就是消息的生产者,它发送的消息将由消息驱动的Bean(即消息消费者)接收。 三、点对点消息队列模式 图五显示了在一个支持点对点消息队列的系统中JMS的基本体系结构。消息队列体系实际 上是核心JMS体系的一个扩展,特别地,它加入了对消息队列功能的支持。连接工厂、连 接、会话、消息生产者、消息消费者等都用点对点消息队列形式的接口进行了扩展。 JMS客户程序利用JNDI获得一个QueueConnectionFactory对象的引用。随后,我们用Que ueConnectionFactory.createQueueConnection()方法之一创建一个QueueConnection对 象的实例。调用createQueueConnection()方法时可以指定一个用户名字和密码,或者, 我们也可以使用该方法不带参数的版本,此时假定使用默认用户身份。 QueueConnection接口是Connection接口的一种子类型,它代表着一个与JMS点对点消息 队列服务的连接。JMS客户程序调用createQueueSession()方法创建QueueSession的实例 ,createQueueSession()方法调用中一个boolean类型的参数指定了QueueSession对象是 否要提供事务支持。另外,回执的模式也在createQueueSession()调用中通过参数指定 ,这个参数的值可以是三个静态的标识符之一:AUTO_ACKNOWLEDGE,CLIENT_ACKNOWLED GE,DUPS_OK_ACKNOWLEDGE。 QueueSession.createQueue()方法返回一个Queue对象的实例,调用Queue.getQueueNam e()方法可以返回队列的名字。 QueueSession.createSender()方法创建一个QueueSender消息生产者,利用QueueSende r可以把消息发送到Queue。消息可以通过各种不同的QueueSender.send()方法发送到Qu eue,这些不同的send()方法能够把消息发送给QueueSender对象关联的Queue对象,或者 发送给send()方法调用中指定的Queue对象。消息递送模式、优先级、消息的有效时间都 可以在调用QueueSender.send()方法时指定。 发送给Queue的消息可以用Session接口中定义的各种消息构造方法创建。 四、发布-订阅消息模式 图六显示了在一个支持发布-订阅消息模式的系统中JMS的基本体系结构。发布-订阅消息 机制也是核心JMS机制的一种扩展,增加了一些适合发布-订阅消息模式的功能。连接工 厂、连接、会话、消息生产者、消息消费者等都用发布-订阅形式的接口进行了扩展。 JMS客户程序通过JNDI获得一个TopicConnectionFactory对象的引用。TopicConnection Factory.createTopicConnection()方法用来创建TopicConnection对象的实例。调用cr eateTopicConnection()方法时可以指定一个用户名字和密码,或者,我们也可以使用该 方法不带参数的版本,此时假定使用默认用户身份。 TopicConnection接口是Connection接口的一种子类型,它代表着一个与JMS发布-订阅消 息服务的连接。JMS客户程序调用TopicConnection.createTopicSession()方法创建Top icSession的实例。会话的事务支持和回执模式也在创建TopicSession时指定。 TopicSession.createTopic()方法返回一个Topic对象的实例。Topic接口封装了一个话 题目的地,发布者向该目的地发送消息,订阅者从该目的地接收消息。不同的服务提供 者按照不同的方式实现话题名称的层次结构,调用Topic.getTopicName()方法可以获得 话题的String形式的描述。 TopicSession.createPublisher()方法创建一个TopicPublisher消息生产者,它用来把 消息发布到Topic。消息可以通过各种不同的TopicPublisher.publish()方法发布到Top ic,这些不同的publish()方法能够把消息发送给TopicPublisher对象关联的Topic对象 ,或者发送给publish()方法调用中指定的Topic对象。消息递送模式、优先级、消息的 有效时间都可以在调用TopicPublisher.publish()方法时指定。 发送给Topic的消息可以用Session接口中定义的各种消息构造方法创建。 五、实例 本示例应用是一个消息驱动Bean应用的简单例子,由以下两部分构成: SimpleMessageClient:J2EE应用客户程序,向队列发送消息。 SimpleMessageEJB:一个消息驱动的Bean,异步地接收和处理由客户程序发送到队列的 消息。 图七描述了这个应用的结构。客户端应用把消息发送到队列,队列由管理员通过j2eead min命令创建。JMS提供者(这里是J2EE服务器)把消息传递给消息驱动Bean的实例,由 Bean的实例处理消息。 该示例应用的完整代码可以从本文最后下载。 5.1 客户端 SimpleMessageClient把消息发送到SimpleMessageBean监听的队列。客户程序首先确定 连接工厂和队列: queueConnectionFactory = (QueueConnectionFactory) jndiContext.lookup ("java:comp/env/jms/MyQueueConnectionFactory"); queue = (Queue) jndiContext.lookup("java:comp/env/jms/QueueName"); 接下来,客户程序创建队列连接、会话和一个消息发送器: queueConnection = queueConnectionFactory.createQueueConnection(); queueSession = queueConnection.createQueueSession(false, Session.AUTO_ACKNOWLEDGE); queueSender = queueSession.createSender(queue); 最后,客户程序把几个消息发送到队列: message = queueSession.createTextMessage(); for (int i = 0; i < NUM_MSGS; i++) { message.setText("我是" + msgArray[i] ); System.out.println("Sending message: " + message.getText()); queueSender.send(message); } 5.2 MDB组件 SimpleMessageEJB类阐明了编写消息驱动Bean类的要求: 实现MessageDrivenBean接口和MessageListener接口。 类定义为public类型。 类不能定义成abstract或final。 实现一个onMessage()方法。 实现一个ejbCreate()方法和一个ejbRemove()方法。 包含一个public类型的不需要参数的构造方法。 不能定义finalize()方法。 与会话Bean和实体Bean不同,消息驱动的Bean不定义客户程序访问的接口。客户程序不 是先定位消息驱动的Bean,再调用这些Bean上的方法。虽然消息驱动的Bean没有业务方 法,但它们可以包含由onMessasge()方法内部调用的辅助方法。 当队列接收到一个消息,EJB容器将调用消息驱动Bean的onMessage()方法。在SimpleMe ssageBean类中,onMessage()方法把接收到的消息定型(cast)成为TextMessage类型, 然后显示出文本信息: public void onMessage(Message inMessage) { TextMessage msg = null; try { if (inMessage instanceof TextMessage) { msg = (TextMessage) inMessage; System.out.println("MESSAGE BEAN:收到消息: " + msg.getText()); } else { System.out.println("消息类型错误: " + inMessage.getClass().getName()); } } catch (JMSException e) { e.printStackTrace(); mdc.setRollbackOnly(); } catch (Throwable te) { te.printStackTrace(); } } 消息驱动Bean的ejbCreate()方法和ejbRemove()方法必须符合以下要求: 访问控制修饰符必须是public。 返回值类型必须是void。 不能有static和final修饰符。 throws子句不能定义任何应用自定义的异常。 不能带有参数。 在SimpleMessageBean类中,ejbCreate()方法和ejbRemove()方法都是空的,不执行任何 有实际意义的操作。 5.3 打包 接下来我们要把上面的应用打包成一个J2EE EAR文件。首先要把SimpleMessageEJB打包 成Jar文件。通常,打包过程可以通过工具完成,但理解模块部署描述器仍是必要的。在 EJB应用模块部署描述器中,顶级元素下面包含元素。下面可以包含一组元素(按照EJB 2.0新规范),每一个元素描述一个消息驱动Bean的配置和部署。 SimpleMessageEJB的ejb-jar.xml文件如下所示。元素内定义了消息驱动Bean的配置和部 署信息,例如唯一的Bean名字、Bean类的名字、配置参数、安全信息、事务信息、消息 目的地类型等。 ...... SimpleMessageJAR SimpleMessageEJB SimpleMessageEJB SimpleMessageBean Container javax.jms.Queue SimpleMessageEJB Bean onMessage javax.jms.Message Required 除了ejb-jar.xml部署描述器之外,通常还要有面向特定平台和环境的部署描述器。大多 数时候,这种描述器可以用GUI工具编写。请参见下载代码中提供的例子。 打包好各个模块之后,接着还要把J2EE应用打包成EAR文件。有关这一步骤的详细说明, 请参见开发平台的相关文档。本文以后有关部署和运行的说明,就以打包后的EAR文件为 基础。 5.4 部署和运行 假设我们在Sun的J2EE参考实现上部署和测试这个示例应用。为便于查看消息驱动Bean的 输出,我们必须以-verbose模式启动服务器: j2ee -verbose 用下面的j2eeadmin命令创建队列: j2eeadmin -addJmsDestination jms/MyQueue queue 验证队列已经创建成功: j2eeadmin -listJmsDestination 启动deploytool,选择菜单“File-->Open”,打开SimpleMessageApp.ear文件。接着, 选择菜单“Tools --> Deploy”,部署应用。出现部署提示时,选中“Return Client JAR”检查框。 在一个命令窗口中,进入EAR文件(SimpleMessageAppClient.jar文件)所在目录,把环 境变量APPCPATH设置为SimpleMessageAppClient.jar。然后,执行下面的命令: runclient -client SimpleMessageApp.ear -name SimpleMessageClient -textauth 在登录提示中,输入用户名字j2ee,输入密码j2ee。此时,客户程序将输出以下内容: Sending message: 我是老大孙悟空 Sending message: 我是老二猪八戒 Sending message: 我是老三沙和尚 在启动j2ee服务器的命令窗口,我们可以看到如下输出: 六、参考资料 下载本文代码:J2EEMessageDrivenEJB_code.zip Enterprise JavaBean Specifications <淘宝热门商品:
 

¥:59.90 

天使之城外贸服装商行(童装/女装)【双皇冠网店 实体店同步】

双皇冠!韩国安卡米文静米色提花高领毛衣,专柜236元,140码

 

98.00 元 

莎莎调配速效去皱眼霜15g 淘宝眼霜销量冠军


来源:程序员网

小小豆叮

Java 中的 XML:文档模型,第一部分:性能

内容: 文档模型 DOM JDOM dom4j Electric XML XML Pull Parser 测试详细信息 性能比较 文档时间 文档遍历时间 文档修改时间 文本生成时间 文档内存大小 Java 序列化 结束语 后续内容... 参考资料 关于作者 对本文的评价 相关内容: 教程:Understanding SAX 教程:Understanding DOM 教程:XML programming in Java 另外在 Web 服务专区: 教程 工具和产品 文章 研究 Java 中 XML 文档模型的特性和性能 Dennis M. Sosnoski(dms@sosnoski.com) 总裁,Sosnoski Software Solutions, Inc. 2001 年 9 月 在本文中,Java 顾问 Dennis Sosnoski 比较几个 Java 文档模型的性能和功能。当选择模型时,无法做到每次都权衡得很清楚,如果以后改变主意,则需要大量编码来进行切换。作者将性能结果放入特性集合的上下文中并遵循标准,对所要求的正确选择给出了一些建议。本文包含用于这组测试的几张图表和源代码。 使用内存中 XML 文档的 Java 开发者可以选择使用标准 DOM 表示或几个 Java 特定模型中的任何一个。该灵活性已经帮助将 Java 建立成 XML 工作的出色平台。但是,由于不同模型数量的增加,已经更加难以确定如何比较模型的功能、性能和易用性。 关于使用“Java 中的 XML”系列中的第一篇文章研究了 Java 中一些领先的 XML 文档模型的特性和性能。它包括一组性能测试的结果(带有可下载的测试代码,请参阅参考资料)。在系列中的第二篇文章将通过比较为实现同样任务所使用的不同模型的样本代码来研究易用性问题。 文档模型 Java 中的可用文档模型数一直在增加。对于本文,我已经涵盖了最常用的模型和几项选择,这演示了那些可能还未被广泛了解或使用的特别令人感兴趣的特性。随着“XML 名称空间”的重要性增加,我已经包含了仅支持该功能的模型。下面列出了带有简要介绍和版本信息的模型。 仅为说明本文中所使用的术语: 解析器是指解释 XML 文本文档结构的程序 文档表示是指程序用于内存中文档的数据结构 文档模型是指支持使用文档表示的库和 API 某些 XML 应用程序根本不需要使用文档模型。如果应用程序可以通过文档的一次遍历搜集它需要的信息,则可能直接使用解析器。该方法可能需要增加一些工作量,但是它的性能总是优于在内存中构建文档表示。 DOM DOM(“文档对象模型”)是用与平台和语言无关的方式表示 XML 文档的官方 W3C 标准。对于任何 Java 特定的模型,它是很好的对照。为了值得与 DOM 标准分开,Java 特定模型应该提供比 Java DOM 实现更优越的性能和/或易用性的优势。 DOM 定义充分利用了 XML 文档不同组件的接口和继承性。这为开发者带来了将公共接口用于几个不同类型组件的优势,但是同时增加了 API 的复杂性。因为 DOM 是与语言无关的,所以接口不需要利用公共 Java 组件,例如,Collections 类。 本文涉及两个 DOM 实现:Crimson 和 Xerces Java。Crimson 是基于 Sun Project X 解析器的 Apache 项目。它合并一个包含 DTD 支持的完整验证解析器。可以通过 SAX2 接口访问该解析器,并且 DOM 实现可以与其它 SAX2 解析器一起工作。Crimson 是在 Apache 许可证下发布的开放源码。用于性能比较的版本是 Crimson 1.1.1(jar 文件大小是 0.2MB),它包含有用于从文本文件的 DOM 构建的 SAX2 解析器。 另一个测试的 DOM 实现,即 Xerces Java 是另一个 Apache 项目。初始时,Xerces 基于 IBM Java 解析器(通常称为 XML4J)。(当前还处于早期 beta 测试版的重新开发的 Xerces Java 2 将最终继承它。当前版本有时称为 Xerces Java 1。)如同使用 Crimson 一样,可以通过 SAX2 接口和 DOM 来访问 Xerces 解析器。然而,Xerces 不提供将 Xerces DOM 与不同的 SAX2 解析器一起使用的任何方法。Xerces Java 包含对 DTD 和 XML Schema 的验证支持(仅带有对 Schema 支持的最小限制)。 Xerces Java 还支持 DOM 的延迟节点扩展方式(请参考本文中的延迟 Xerces 或 Xerces def.),其中文档组件初始时是以压缩格式表示的,仅当使用时才将它扩展成完整的 DOM 表示。这种方式的用意是允许更快的解析并降低内存的使用,尤其对于那些可能仅使用部分输入文档的应用程序。与 Crimson 类似,Xerces 是在 Apache 许可证下发布的开放源码。用于性能比较的版本是 Xerces 1.4.2(jar 文件大小是 1.8MB)。 JDOM JDOM 的目的是成为 Java 特定文档模型,它简化与 XML 的交互并且比使用 DOM 实现更快。由于是第一个 Java 特定模型,JDOM 一直得到大力推广和促进。正在考虑通过“Java 规范请求 JSR-102”将它最终用作“Java 标准扩展”。虽然实际将采用的格式仍在开发中,还是对两个 beta 测试版的 JDOM API 做了很大的更改,。从 2000 年初就已经开始了 JDOM 开发。 JDOM 与 DOM 主要有两方面不同。首先,JDOM 仅使用具体类而不使用接口。这在某些方面简化了 API,但是也限制了灵活性。第二,API 大量使用了 Collections 类,简化了那些已经熟悉这些类的 Java 开发者的使用。 JDOM 文档声明其目的是“使用 20%(或更少)的精力解决 80%(或更多)Java/XML 问题”(根据学习曲线假定为 20%)。JDOM 对于大多数 Java/XML 应用程序来说当然是有用的,并且大多数开发者发现 API 比 DOM 容易理解得多。JDOM 还包括对程序行为的相当广泛检查以防止用户做任何在 XML 中无意义的事。然而,它仍需要您充分理解 XML 以便做一些超出基本的工作(或者甚至理解某些情况下的错误)。这也许是比学习 DOM 或 JDOM 接口都更有意义的工作。 JDOM 自身不包含解析器。它通常使用 SAX2 解析器来解析和验证输入 XML 文档(尽管它还可以将以前构造的 DOM 表示作为输入)。它包含一些转换器以将 JDOM 表示输出成 SAX2 事件流、DOM 模型或 XML 文本文档。JDOM 是在 Apache 许可证变体下发布的开放源码。用于性能比较的版本是 JDOM Beta 0.7(jar 文件大小是 0.1MB)它带有用于从文本文件构建 JDOM 表示的 Crimson SAX2 解析器。 dom4j 虽然 dom4j 代表了完全独立的开发结果,但最初,它是 JDOM 的一种智能分支。它合并了许多超出基本 XML 文档表示的功能,包括集成的 XPath 支持、XML Schema 支持(当前为 alpha 格式)以及用于大文档或流化文档的基于事件的处理。它还提供了构建文档表示的选项,它通过 dom4j API 和标准 DOM 接口具有并行访问功能。从 2000 下半年开始,它就一直处于开发之中,保留了最近发行版之间的现有 API。 为支持所有这些功能,dom4j 使用接口和抽象基本类方法。dom4j 大量使用了 API 中的 Collections 类,但是在许多情况下,它还提供一些替代方法以允许更好的性能或更直接的编码方法。直接好处是,虽然 dom4j 付出了更复杂的 API 的代价,但是它提供了比 JDOM 大得多的灵活性。 在添加灵活性、XPath 集成和对大文档处理的目标时,dom4j 的目标与 JDOM 是一样的:针对 Java 开发者的易用性和直观操作。它还致力于成为比 JDOM 更完整的解决方案,实现在本质上处理所有 Java/XML 问题的目标。在完成该目标时,它比 JDOM 更少强调防止不正确的应用程序行为。 dom4j 使用相同方法作为 JDOM 输出,这依靠 SAX2 解析器输入处理,依靠转换器将输出处理成 SAX2 事件流、DOM 模型或 XML 文本文档。dom4j 是在 BSD 样式许可证下发布的开放源码,该许可证本质上等价于 Apache 样式许可证。用于性能比较的版本是 dom4j 0.9(jar 文件大小是 0.4MB),带有用于从文本文件构建表示的受绑定 AElfred SAX2 解析器(由于 SAX2 选项设置,测试文件之一无法由 dom4j 使用用于 JDOM 测试的同一 Crimson SAX2 解析器来处理)。 Electric XML Electric XML(EXML)是支持分布式计算的商业项目的附属产物。它与目前为止讨论的其它模型的不同之处在于,它只能适当地支持 XML 文档的子集,它没有为验证提供任何支持并且有更严格的许可证。然而,EXML 的优势是大小很小并提供了对 XPath 子集的直接支持,因为在最近几篇文章中已经将它提升其它模型的替代模型,所以通过该比较使它成为一个引人注意的候选。 虽然 EXML 通过使用抽象的基本类方法取得了某些相同效果,但它在避免使用接口方面使用与 JDOM 类似的方法(主要区别是接口为扩展实现提供了更大的灵活性)。它与 JDOM 的不同之处还在于避免使用 Collections 类。该组合为其提供了非常简单的 API,在许多方面类似于带有附加 XPath 操作的 DOM API 简化版本。 仅当空白与非空白文本内容邻近时,EXML 才在文档中保留空白,这就将 EXML 限制成 XML 文档的一个子集。标准 XML 需要在读取文档时保留该空白,除非对文档 DTD 可以确认有无空白无关紧要。对于事先已经知道空白无关紧要的许多 XML 应用程序来说,EXML 方法工作得很好,但是它防止对于期望保留空白的文档(例如,生成由浏览器显示或查看的文档的应用程序)使用 EXML。(有关作者对于该主题的谦虚建议,请参阅副栏使用空白的目的。) 这种空白的删除会对性能比较产生误导效果 — 许多类型的测试范围与文档中的组件个数成比例,并且由 EXML 删除的每个空白序列都是其它模型中的组件。EXML 包含在本文显示的结果中,但是解释性能差异时请记住这种影响。 EXML 使用集成的解析器依据文本文档构建文档表示。除了通过文本方式外,它不提供从 DOM(或 SAX2)转换或转换成 SAX2(或 DOM)事件流的任何方式。EXML 是由 Mind Electric 在禁止将它嵌入某些类型的应用程序或库的受限许可证下发布的开放源码。用于性能比较的版本是 Electric XML 2.2(jar 文件大小是 0.05MB)。 XML Pull Parser XML Pull Parser (XPP)是最近开发的,它演示了 XML 解析的不同方法。与 EXML 一样,XPP 只能适当支持 XML 文档的子集并且不提供验证的任何支持。它同样具有尺寸小的优势。这种优势再与拉回解析器方法结合,使它成为该比较中的良好替换项。 XPP 几乎独占地使用接口,但是它仅使用所有类中的一小部分。和 EXML 一样,XPP 避免使用 API 中的 Collections 类。总的来说,它是本文中最简单的文档模型 API。 将 XPP 限制成 XML 文档子集的局限性是它不支持文档中的实体、注释或处理指示信息。XPP 创建仅包含元素、属性(包括“名称空间”)和内容文本的文档结构。这对于某些类型的应用程序来说是一种非常严格的限制。但是通常它对性能的影响比 EXML 空白处理对性能的影响小。在本文中我仅使用了一个与 XPP 不兼容的测试文件,并且在带有注释的图表中显示了 XPP 结果,该注释不包含该文件。 XPP 中的拉回解析器支持(本文中称为 XPP 拉回)通过将解析实际上推迟到访问文档的一个组件时才进行,然后按照构造那个组件的需要对文档进行解析。该技术想实现允许非常快速的文档显示或分类应用,尤其在需要转发或除去(而不是对文档进行完全解析和处理)文档时。该方法的使用是可选的,如果以非拉回型方式使用 XPP,它对整个文档进行解析并且同时地构建完整的表示。 与 EXML 一样,XPP 使用依据文本文档构建文档表示的集成语法解析器,并且除了通过文本方式外,它不提供从 DOM(或 SAX2)转换或转换成 SAX2(或 DOM)事件流的任何方式。XPP 是具有 Apache 样式许可证的开放源代码。用于性能比较的版本是 PullParser 2.0.1 Beta 8(jar 文件大小是 0.04MB)。 测试详细信息 所显示的计时结果是来自使用 Sun Microsystems Java version 1.3.1、Java HotSpot Client VM 1.3.1-b24 测试,这些软件是运行在带有 256MB RAM 的 Athlon 1GHz 系统上的 Redhat Linux 7.1 下。将这些测试的初始 JVM 和最大内存大小都设置成 128MB,我想将它表示为服务器类型执行环境。 在使用初始缺省 JVM 内存设置为 2MB 和最大内存为 64MB 运行的测试中,带有较大 jar 文件大小(DOM、JDOM 和 dom4j)的模型的结果非常差,尤其在运行测试的平均时间中。这可能是由于内存受限执行的 HotSpot JVM 的无效操作引起的。 文档模型中的两种(XPP 和 EXML)支持直接将文档输入成“字符串”或字符数组。该类型直接输入不能代表实际应用程序,因此我在这些测试中避免使用它。对于输入和输出,我使用 Java 流封装字节以消除 I/O 对性能的影响,而保留了用于 XML 文档输入和输出的应用程序在典型情况下使用的语言接口。 性能比较 本文中使用的性能比较基于对一组选中的 XML 文档进行的解析和使用,这些文档试图代表较大范围的应用程序: much_ado.xml,标记成 XML 的莎士比亚戏剧。没有属性并且是相当简单的结构(202K 字节)。 periodic.xml, XML 中的元素的周期表。一些属性,也是相当简单的(117K 字节)。 soap1.xml,取自规范的样本 SOAP 文档。大量名称空间和属性(0.4K 字节,每次测试需要重复 49 次)。 soap2.xml,SOAP 文档格式中的值列表。大量名称空间和属性(134K 字节)。 nt.xml,标记为 XML 的“新约”。没有属性并且非常简单的结构,大量文本内容(1047K 字节)。 xml.xml,XML 规范,不带 DTD 引用,在内部定义所有实体。带有大量混合内容的文本样式标记,一些属性(160K 字节)。 关于测试平台的更多信息,请参阅副栏测试详细信息并查看参考资料以获取用于测试的源代码的链接。 除了非常小的 soap1.xml 文档之外,所有评测时间都是指文档的每次特定测试所经历的时间。在 soap1.xml 的情况下,评测的时间是 49 个连续的文档测试(总数为 20K 字节文本的足够副本数)。 测试框架在一个文档上运行一个特定的测试多次(这里显示运行了 10 次),依此跟踪该测试的最短时间和平均时间,然后继续同一文档上的下一个测试。完成对一个文档的全部测试序列后,它对下一个文档重复该过程。为防止文档模型之间的交互,在执行每个测试框架时仅测试一个模型。 HotSpot 以及类似于动态优化 JVM 的计时基准程序是出了名的棘手的;测试序列中的小变化经常导致计时结果发生很大变化。我已经发现对于执行特定代码段的平均时间时,确实如此;最短时间比较一致,正是我在这些结果中列出的值。可以参阅第一次测试(文档构建时间)的平均和最短时间的比较。 文档构建时间 文档构建时间测试检查解析文本文档和构造文档表示所需的时间。出于比较目的,已经在图表中包含了使用 Crimson 和 Xerces SAX2 解析的 SAX2 解析时间,因为大多数文档模型(除了 EXML 和 XPP 外的所有文档)使用 SAX2 解析事件流作为文档构建过程的输入。图 1 描述了测试结果。 图 1. 文档构建时间 对于大多数测试文档来说,XPP 拉回的构建时间太短以至于难以计算(因为在这种情况下,实际上没有对该文档进行解析),只显示为非常短的 soap1.xml。对于该文件,拉回解析器内存大小和相关的创建开销使 XPP 显得相对比较缓慢。这是因为测试程序为正在进行解析的文档的每个副本创建一个新的拉回解析器副本。在 soap1.xml 情况下,每次评测时间使用 49 个副本。分配与初始化这些解析器实例的开销大于重复解析文本并构建文档表示的大多数其它方法所需的时间。 XPP 的作者在一个电子邮件的讨论中指出,在实际应用程序中,可以合用拉回解析器实例以重新使用。如果这样做的话,soap1.xml 文件的开销将明显降到忽略不计程度。对于更大的文件,甚至不需要合用,拉回解析器创建开销也可以变得忽略不计。 在本测试中,XPP(带有完整解析),带有延迟节点创建的 Xerces 和 dom4j 都显示整体上的同等性能。延迟的 Xerces 对于较大的文档尤其出色,但是对于较小的文档的开销较高 — 甚至比常规 Xerces DOM 高很多。在第一次使用文档的一部分时,延迟节点创建方法的开销也较高,这会降低快速解析的优势。 对于较小的 soap1.xml 文件,所有格式(SAX2 解析、常规 DOM 和延迟 DOM)的 Xerces 的显得开销较高。对于该文件 XPP(完全解析)尤其出色,对于 soap1.xml,EXML 甚至超过基于 SAX2 的模型。虽然 EXML 具有废弃单独的空白内容的优势,但是总体上,它是本测试中最差的。 文档遍历时间 文档遍历时间测试检查遍历构造的文档表示所需的时间,按文档顺序遍历每个元素、属性和文本内容段。它试图表示文档模型接口的性能,这对于从进行过解析的文档中重复访问信息的应用程序来说可能很重要。总体上,遍历时间比解析时间快得多。对于只对解析过的文档单次遍历的应用程序,解析时间将比遍历时间更重要。图 2 显示了结果。 图 2. 文档遍历时间 在本测试中,XPP 的性能大大超过了其余的测试对象。Xerces DOM 所花费的时间大约是 XPP 的两倍。虽然 EXML 具有废弃文档中单独的空白内容的优势,但是,EXML 花费的时间几乎是 XPP 的三倍。dom4j 在这张图中处于中间位置。 使用 XPP 拉回时,直到访问文档表示时才真正发生对文档文本的解析。这导致第一次遍历文档表示时的开销非常大(表中未显示)。如果以后访问整个文档表示,则当使用拉回解析方法时,XPP 显示性能的净损失。对于拉回解析器来说,前两个测试所需的总时间比使用 XPP 的常规解析长(长 20% 到 100%,这取决于文档)。但是,当还未完全访问正在进行解析的文档时,拉回解析器方法仍然具有可观的性能优势。 带有延迟节点创建的 Xerces 显示了相似的行为,第一次访问文档表示时导致性能下降(图中未显示)。但是,在 Xerces 情况下,节点创建开销大约与解析期间常规 DOM 创建的性能差值相同。对于较大的文档来说,用 Xerces 延迟的前两次测试所需的总时间大致与使用带常规 DOM 构建的 Xerces 所用的时间相同。如果在非常大的文档(可能 10KB 或更大)上使用 Xerces,则延迟的节点创建似乎是一个好选择。 文档修改时间 这个测试检查系统地修改构造文档表示所需的时间,其结果在图 3 中显示。它遍历表示,删除所有单独的空白内容并且用新添加的元素封装每个非空白内容字符串。它还向包含非空白内容的原始文档的每个元素中添加一个属性。该测试试图表示经过一定范围文档修改后文档模型的性能。如遍历时间一样,修改时间比解析时间短很多。因此,对于仅单次遍历每个解析过的文档的应用程序来说,解析时间将更重要。 图 3. 文档修改时间 这次测试中 EXML 处于领先地位,但是由于在解析期间它总是废弃单独的空白内容,它才比其它模型具有性能上的优势。这意味着在测试期间没有要从 EXML 表示中进行删除的内容。 在修改性能方面,XPP 仅次于 EXML,并且与 EXML 不同,XPP 测试包含删除。Xerces DOM 和 dom4j 接近地处于中间位置,JDOM 和 Crimson DOM 模型的性能仍是最差。 文本生成时间 这个测试检查将文档表示输出成文本 XML 文档所需的时间;结果显示在图 4 中。对于不专门使用 XML 文档的任何应用程序,该步骤似乎是整体性能的一个重要部分,特别是因为将文档输出为文本所需的时间总体接近于对文档输入进行解析所需的时间。为使这些时间具有直接的可比性,该测试使用原始文档,而没有使用由前面的测试所生成的已修改文档。 图 4. 文本生成时间 文本生成时间测试表明各模型之间的差别小于前面测试中各项的差别,Xerces DOM 性能最好,但领先不多,JDOM 性能最差。EXML 的性能优于 JDOM,但是这同样是由于 EXML 废弃空白内容。 许多模型提供了控制文本输出格式的选项,并且一些选项似乎影响文本生成时间。这个测试只使用每个模型的最基本的输出格式,因此结果只显示缺省性能而不显示最好的可能性能。 文档内存大小 这个测试检查用于文档表示的内存空间。这对于使用大文档或同时使用多个较小文档的开发者来说,意义尤为重要。图 5 显示这个测试的结果。 图 5. 文档内存大小 内存大小结果与计时测试不同,因为小的 soap1.xml 文件显示的值表示文件的单个副本而不表示在计时评测中使用的 49 个副本。在大多数模型中,用于简要文档的内存太小以至于无法在图的刻度上显示。 除了 XPP 拉回(直到访问它时才真正构建文档表示)之外,与一些计时测试中显示的差别相比,内存大小测试中模型之间的差别相对较小。延迟的 Xerces 具有最紧凑的表示(当第一次访问表示时将它扩展成基本 Xerces 大小),紧接着是 dom4j。虽然 EXML 废弃包含在其它模型中的空白内容,但是它仍具有最不紧凑的表示。 因为即使最紧凑的模型也要占用大约原始文档文本大小(以字节计)四倍的空间,所以对于大文档来说,所有模型似乎都需要太多的内存。通过提供使用部分文档表示的方法,XPP 拉回和 dom4j 为非常大的文档提供了最好的支持。XPP 拉回通过仅构建实际被访问的表示部分完成该任务,而 dom4j 包含对基于事件处理的支持,使得一次只构建或处理文档的一部分。 Java 序列化 这些测试评测文档表示的 Java 序列化的时间和输出大小。这主要涉及那些使用 Java RMI(“远程方法调用”)在 Java 程序之间传送表示的应用程序(包括 EJB (Enterprise JavaBean) 应用程序)起作用。在这些测试中,仅包含了那些支持 Java 序列化的模型。下列三张图显示了该测试的结果。 图 6. 序列化输出时间 图 7. 序列化输入时间 图 8. 序列化文档大小 dom4j 显示了输出(生成序列化的格式)和输入(从序列化的格式重新构建文档)的最好的序列化性能,而 Xerces DOM 显示了最差的性能。EXML 所花费的时间接近 dom4j,但是 EXML 还是具有在表示中使用较少数量对象的优势,因为它废弃空白内容。 如果将文档输出成文本然后进行解析以重新构建文档,而不是使用 Java 序列化,则所有性能 — 时间和大小 — 都会好得多。这里的问题是作为大量唯一的小对象的 XML 文档表示的结构。Java 序列化无法有效处理这种类型的结构,这导致时间和输出大小的开销都很高。 可以设计比文本表示小且比文本输入和输出快的文档序列化格式,但是只能通过绕过 Java 序列化来完成。(我有一个项目实现 XML 文档的这种定制的序列化,在我公司的 Web 站点上可以找到其开放源码,请参阅参考资料。) 结束语 不同的 Java XML 文档模型各有所长,但是从性能观点来看,有些模型具有明显的优势。 在大多数方面,XPP 性能处于领先地位。尽管 XPP 是一种新模型,但是对于不需要验证、实体、处理指示信息或注释的中间件类型应用程序来说,它是非常好的选择。它尤其适用于作为浏览器小应用程序或在内存受限的环境下运行的应用程序。 虽然 dom4j 没有与 XPP 同等的速度,但是,它确实提供了具备更标准化的优越性能和功能更全的实现,包括对 SAX2、DOM 甚至 XPath 的内置支持。虽然 Xerces DOM(带有延迟的节点创建)对于小文件和 Java 序列化性能不佳,但是在大多数评测时仍然出色。对于常规 XML 处理,dom4j 和 Xerces DOM 都是很好的选择,对它们的选择取决于您认为是特定于 Java 的特性更重要还是跨语言的兼容性更重要。 JDOM 和 Crimson DOM 在性能测试时一直表现不佳。在小文档情况下还值得考虑使用 Crimson DOM,而 Xerces 表现很差。虽然 JDOM 的开发者已经说明他们期望在正式发行版前专注性能问题,但是从性能观点来看,它确实没有值得推荐之处。然而,如果不进行 API 的重新构建,JDOM 可能难以达到与其它模型匹配的性能。 使用空白的目的 XML 规范通常需要保留空白,但是许多 XML 应用程序使用仅为可读性而保留空白的格式。对于这些应用程序,EXML 废弃隔离空白的方法起了作用。 这些性能中使用的大多数文档属于“为可读性而保留的空白”类别。这些文档被格式化成便于人们查看的形式,一行最多一个元素。结果,无关的空白内容字符串数实际上超过了文档中的元素数量。这大大增加了每一步处理的不必要开销。 支持修剪输入上这种类型空白的选项将有助于提高带有可忽略的空白的应用程序的所有文档模型的性能(除了 EXML 之外)。只要修剪是一个选项,它就不会影响需要完全保留空白的应用程序。解析器级别的支持将更好,因为解析器必须逐一处理输入字符。总之,这种类型的选项将非常有助于许多 XML 应用程序。 EXML 非常小(以 jar 文件大小为单位)并且在一些性能测试中表现良好。虽然 EXML 具有删除单独空白内容的优势,但是在性能方面不如 XPP。除非您需要 EXML 支持而 XPP 缺少的一种特性,否则在内存受限的环境下,XPP 可能是更好的选择。 虽然 dom4j 性能最好,但是,当前没有一种模型能为 Java 序列化提供良好性能。如果需要在程序之间传递文档,通常的最佳选择是将文档写成文本然后进行解析以重新构建表示。将来,定制序列化格式可能提供一个更好的选择。 后续内容... 我已经涵盖了一些文档模型的基本特性,并且显示了几种类型文档操作的性能评测。请记住,虽然,性能只是选择文档模型的一个因素。对于大多数开发者,可用性至少与性能一样重要,并且这些模型使用不同的 API 都可能有喜欢这个而不喜欢那个的理由。 在后续文章中将集中研究可用性,其中我将比较用于完成这些不同模型中相同操作的样本代码。请检查本比较的第二部分。当您等待时,可以通过下面的论坛中的链接提出您对本文的评论和问题与大家共享。 参考资料 参加关于本文的论坛。 如果您需要背景知识,请尝试 developerWorks XML programming in Java、Understanding SAX tutorial 和 Understanding DOM tutorial。 从下载页面下载用于本文的测试程序和文档模型库。 在测试程序的主页上查看更新的测试和测试结果。 获取作者关于 XML Serial (XMLS) encoding 工作的详细信息作为 Java 序列化的替代项。 研究或下载本文中讨论的 Java XML 文档模型: Xerces Java Crimson JDOM dom4j Electric XML(EXML) XML Pull Parser(XPP) IBM WebSphere Application Server 包含基于 Xerces Java 的 XML4J 解析器。可在 WAS Advanced edition 3.0 online documentation 中找到关于产品 XML 支持的 how-to 信息。 关于作者 Dennis Sosnoski(dms@sosnoski.com)是西雅图地区 Java 咨询公司 Sosnoski Software Solutions, Inc. 的创建者和首席顾问。他具有 30 多年的专业软件开发经验,最近几年,他集中研究服务器方 Java 技术,包括 servlet、Enterprise JavaBeans 和 XML。他已经多次演示了 Java 性能问题和常规服务器端的 Java 技术,他还是 Seattle Java-XML SIG 的主席。 <淘宝热门商品:
 

88.00 元 

双皇冠 狂卖2000条!Levis 超赞牛仔裤

 

288.00元  

【果然瘦身】(关于减肥药)瘦脸/瘦腿/小腰(专业指导你减肥)


来源:程序员网

小小豆叮

Java Api for XML 与 XML 标准的对应

当今最新最热的技术可以分为WebService和microsoft .net两大阵营。今年在上海举行的"Sun科技日", Sun, Bea, Oracle的公司都介绍了对WebService的支持。 Webservice这个最新的技术的核心是XML。由于java 和 XML是梦幻组合,当然对每个XML的标准提供了相应的API, 为了方便各位developer的开发,我在此列出了api 与 XML 标准的对应: ________________________________________________________________________ | XML Standard | Java API for XML | Description | +-------------------+------------------------+---------------------------+ | DOM, SAX, XSL | JAXP |Java Apis for XML Parsing | +-------------------+------------------------+---------------------------+ | SOAP/ebXML | JAXM |Java APIs for XML Messaging| +-------------------+------------------------+---------------------------+ | SOAP | JAX-RPC |Java APIs for XML Remote | | | |Procedure Call | +-------------------+------------------------+---------------------------+ | XML | JAXB |Java APIs for XML Binding | +-------------------+------------------------+---------------------------+ | WSDL | JAX-WSDL | Java APIs for WSDL | +-------------------+------------------------+---------------------------+ | UDDI | JAXR | Java APIs for XML Register| _______________________________________________________________________ <淘宝热门商品:
 

¥:21.0 

【华佗天然居】天然花草茶花茶中草药中药材

花草茶之瘦腿茶:迷迭香+柠檬草+马鞭草30包21元包快递美容减肥茶

 

88.00 元  

【广州商盟】外贸男装、男鞋工厂直接供货批发零售

〖亿贝特价〗外贸原单Versace范思哲多LOGO特色羊毛衫、毛衣V灰紫


来源:程序员网

小小豆叮

使用 JMS 技术作为数据复制的解决方案

本文概述了如何使用 Java 消息传递系统(JMS)进行大型文件的复制。Dan Drasin 描 述了解决 Applied Reasoning 公司客户的分布式数据问题的方案,并提供了基于 JMS 的解决方案的实现细节。他讨论了其中的优点、一些潜在缺陷以及将 IBM MQSeries(现 在称为 WebSphere MQ)成功设置为 JMS 服务器的一些实际指示信息。 背景 在思考消息传递解决方案时,您可能会想到一个通过远程消息调用机制来集成两个不同 应用程序的系统。一般来讲,对于不常通信的分布式实体以及数据传输量不是很多这样 的情况,常常使用这种耦合。较经典的示例是,连接到异构后端和入口的同构接口,这 些后端和入口指派进行用户请求的后端处理,然后为最终用户表示而对那些请求进行重 新格式化。 消息传递方法中的公共线程一直有这样的假定:虽然消息传递解决方案在系统之间提供 健壮、高度可用的通信,但它基本上效率很低,只用来作为在无法避免与外部系统通信 时的最后一种手段。在出现远程方法调用(RMC)时关于消息传递的这种观点就开始流行 一直到出现了更现代的象 CORBA 和 DCOM 那样的消息传递解决方案,而且,通常所应用 的消息传递只局限于解决几类问题。 目标 在过去的十年中,人们对分布式系统需求有了更深入的理解。新兴技术(象 Java 和 . NET)已经包含了代码分布来作为它们基本编程模型的一部分。通过这样做,这些技术已 将高度可用性和容错性融入到消息传递中,同时鼓励那些提供解决方案的供应商交付一 些系统,这些系统在更广范围的问题上考虑性能。 近来我们公司被要求实现文件分布和复制的解决方案,在以前这样的方案需要集成安全 的 FTP、数据库复制和其它一次性解决方案的定制系统。我们没有一味地埋头按照定制 开发的道路前进,而是研究了将最新的消息传递解决方案应用到这个问题的可能性。我 们发现 JMS 不仅为信息传送提供必要的基础结构,而且它还能处理我们客户要求的、与 服务质量、安全性、可靠性和性能有关的所有基础结构问题。本文描述了我们团队面临 的挑战,以及 JMS(以 MQSeries 的形式)如何让我们满足并超越客户的要求。 问题 我们的客户面临一个重大的分布式数据难题,在全国范围内有许多呼叫中心,在全国各 地的呼叫中心里接线员要记录与客户之间的交互。必须快速可靠地在远程数据中心为这 些记录建立索引并存档。建立索引和存档的存储过程不能影响接线员的系统记录和存储 接线员正在与客户交互的信息的能力。该客户已经有了一个包含组合起来的代码、VPN 和其它技术的系统。但是,现有的解决方案远远达不到性能和可靠性上的目标,并且它 是一种拙劣的技术,难以理解并且维护费用很高。 在开发替代客户原有系统时,我们考虑了 JMS 和多种非 JMS 的解决方案,尤其是那些 基于 FTP 和安全复制(SCP)的解决方案。然而,非 JMS 解决方案有两个主要缺点: 它们对于安全性方面的缺陷一筹莫展。(FTP 上的安全性漏洞已经人人皆知,并且人们 对此已广泛地作了记载。如果需要这方面的例子,请参阅参考资料。) 它们提供的基础结构只适用于实际的数据传送,而对于处理可靠性、容错性、安全性、 平台独立性以及性能优化等问题,需要定制开发来解决。 我们团队最后得出结论,对于添加这些额外的特性所需的开发工作是让人望而却步的, 因此我们决定选用 JMS 解决方案,它可以摆脱这些问题。 解决方案 我们开发了一个基于 JMS 的系统,它: 为已记录的多媒体文件提供可靠存档 支持可扩展性,可以使多个数据中心接收文件 支持对其它数据类型进行存档 我们这里正讨论的文件比以前那些涉及消息传递解决方案的项目中传送的数据还要大( 50K - 500K)。我们第一个任务是确保数据大小不会影响 JMS 解决方案。通过测试系统 传递各种大小的消息有效负载时的性能,我们评估了包括 IBM MQSeries 在内的许多 J MS 解决方案。结果显示:经过适当配置,大小达到 1 兆的消息不会对整个系统性能产 生显著影响。因为常识认为消息传递解决方案只适用于定期的、小的有效负载,所以我 们的结果是一个重大发现。我们继续分析系统的体系结构(图 1 中概述了此体系结构) ,它可以提供客户需要的安全性、高可用性和可靠性。 图 1. 高级系统体系结构 现有的基础结构在每个客户机上有一个系统,当接线员与用户之间进行交互时,它创建 多媒体文件,以此作为响应。此外,还需对这些文件进行存档。我们的系统启动一个进 程(运行在每个机器上)并在已知目录中查找这些文件。当检测到新文件时,进程将它 们打包成 JMS 有效负载并发送到其中一个数据中心的 JMS 服务器以便传递。一旦 JMS 服务器确认收到,则除去发送方中的这些文件。JMS 服务器将该数据传送到数据中心内 的一个可用处理程序上,进行存档。 主要概念 JMS 是特定于 Java 的消息传递和排队的实现。在消息传递和排队中有两个基本思想: 系统通过使用不连续的数据包进行通信,这些数据包都有一个有效负载(即要传送的信 息)和属性(即该信息的特征以及它应如何通信)。这个数据包称为 消息。 消息不是被发送给系统,而是被发送到一个独立的保存区域。可以根据您的需要确定保 存区域的数量,通过唯一的名称,可以标识并定位它们。每个保存区域都可以接收消息 ,并且根据配置的不同,该区域将每个消息要么传递给所有感兴趣的系统(发布-订阅) ,要么传递给第一个感兴趣的系统(点对点)。这个保存区域称为 目的地。 我们构建的系统采用点对点的目的地,在 JMS 中称为队列。排队是图 1 中显示的系统 设计的一个重要方面。该图显示了消息正从 JMS 代理直接传送到接收方的客户机上,但 这并不十分准确。实际上,消息被传送到一个队列中,接收方客户机从队列中检索它们 。稍后我们研究实现细节时,这个区别将变得非常重要,因为它让系统并行地处理收到 的消息。 跨平台和交叉供应商 对我们客户机来说尽量减少对某家供应商的依赖,这意味着,我们所设计的代码应该使 由于更改了 JMS 供应商而带来的影响降至最低,这是十分重要的。JMS 的一个主要优点 是它以广泛的业界支持和开放标准为基础,因此有了正确设计的代码,我们就可以让系 统使用任何 JMS 系统。(可以对现有系统进行直接改进,专门设计来使系统在某套硬件 上运行并能与特定于供应商的解决方案相匹配。) 通过将所有特定于供应商的调用封装在称为 JMSProvider 的类中,就可以轻松实现平台 独立性。这些 Provider 类处理特定于供应商的问题,例如工厂查询、错误处理、连接 创建和消息特性设置等。请参阅下面清单 1 中的示例代码。 清单 1. 在类 ar.jms.JmsProvider 中 public QueueConnection createConnection() throws JMSException { return getConnectionFactory().createQueueConnection(getUserName(), getPassword()); } 通过利用“Java 命名和目录接口(JNDI)”,我们将特定于供应商的设置存储在一个资 源库(例如,LDAP 库)中,这样实际代码就几乎不需要特定于供应商的引用。只需要少 量特定于供应商的代码来处理一些特性,但是可以将这样的代码限定于一些“适配器” 类,并将它保存在应用程序代码之外。请参阅下面清单 2 中的示例代码。因为 JMS 被 设计用来方便地使用 JNDI,所以与其它解决方案相比,这是另一个直接优点 ― 配置信 息的集中存储不仅可以保存基于文本的信息,而且还可以存储已配置的对象。 清单 2. 在类 ar.jms.JmsProvider 中 public final static String CONNECTION_FACTORY_LOOKUP_NAME_KEY = "CONNECTION_FACTORY_LOOKUP_NAME"; public final static String FILE_TRANSFER_QUEUE_LOOKUP_NAME_KEY = "FILE_TRANSFER_QUEUE_LOOKUP_NAME"; public final static String JMS_PROVIDER_CLASS_KEY = "JMS_PROVIDER_CLASS"; public void init() throws NamingException { InitialContext jndi = createInitialContext(); initConnectionFactory(jndi); initFileTransferQueue(jndi); } public QueueConnection createConnection() throws JMSException {return getConnectionFactory().createQueueConnection(getUserName(), getPassword()); } public void initConnectionFactory(InitialContext jndi) throws NamingException { setConnectionFactory((QueueConnectionFactory)jndi.lookup (getProperties().getProperty(CONNECTION_FACTORY_LOOKUP_NAME _KEY))); } public void initFileTransferQueue(InitialContext jndi) throws NamingException { setFileTransferQueue((Queue) jndi.lookup (getProperties().getProperty(FILE_TRANSFER_QUEUE_LOOKUP_NAM E_KEY))); } 跳出传统模式,JMS 解决方案允许以可靠的方式传送消息,即一旦确认已将消息传送到 JMS 服务器,就将它传送至寻址到的目的地(队列)。MQSeries 也不例外。一旦成功 执行了将消息发送到服务器的代码,客户机就保证目的地最终会接收到消息,即使所讨 论的服务器在处理过程中出现故障(如果目的地暂时不可用,或者 JMS 服务器死机等等 )。请参阅下面清单 3 中的示例代码。下面代码中的类实际上负责一旦它确定需要发送 文件,就执行数据的发送。 通过将消息配置为持久消息,我们可以保证一旦目的地(队列)接收到消息,那么消息 将保留在那里直到它在该队列中被检索为止 ― 即使在系统有故障期间。因此,一旦安 全地将消息传送到本地 JMS 服务器,就可以删除它了。不能过高估计克服系统故障的能 力;对周期性系统故障的处理是开发分布式存档解决方案最重要的问题之一。客户现有 系统上处理故障情况的代码很复杂很脆弱,而且对这些故障的处理和维护费用很高。通 过一个健壮的、经测试成功的商业解决方案,JMS 使我们能解决所有这些问题。 清单 3. 来自类 ar.jms.file.send.ConnectionElement public void sendMessage(byte[] payload, boolean persistent) throws SendFailedException { QueueSender sender = null; try { Message message = createMessage(payload); sender = createSender (persistent ? DeliveryMode.PERSISTENT : DeliveryMode.NON_PERSISTENT); sender.send(message); getClient().getLogService().logInfo(getName() + " sent message " + message.getJMSMessageID() + "."); } catch (JMSException exception) { getClient().getLogService().logError ("JMS exception processing " + getName(),exception); stop(); throw new SendFailedException("JMS Message Send Failed"); } try { sender.close(); } catch (JMSException ignore) { getClient().getLogService().logInfo(getName() + " failed to close sender. Processing will continue."); } } 这个解决方案的关键是配置 JMS 消息和服务器来同时提供令人满意的性能和服务质量。 JMS 规范定义了配置选项,并通过所有商业解决方案实现它们。但是,配置的确切方法 根据不同的供应商而有所不同。 设置 我们创建的体系结构和系统具有通用性且很强大。但是,对于一些移动部件,必须使用 正确的方式配置并钩连它们。以下内容是有关将 MQSeries 成功地设置为 JMS 服务器的 概述、一些潜在缺陷和实际的指示信息。 对于 MQSeries,首先设置 JNDI 服务器来检索特定于实现的设置,在这种情况下是 JM S 连接工厂(JMS Connection Factory)。有许多不同方法来实现这个操作,但适宜的 通用选项是轻量级目录访问协议(LDAP)服务器。我们选择使用 Qualcomm SLAPD。一旦 安装好并运行该服务器,就可以用 MQSeries 管理工具(JMSAdmin.bat)来设置该服务 器并将其作为 MQ 对象信息库来使用。请参阅参考资料,获取有关讲述该过程的实用书 籍的链接。同时,在设置期间,要特别注意在 IBM MQSeries 之上设置 JMS 的 IBM 文 档,这很重要。这个过程涉及创建一些队列和其它对象,这些队列和对象是特定于 JMS 使用并且不属于标准 MQSeries 安装的。 完成 JNDI/LDAP 和 JMS 服务器的设置后,就可以准备配置客户机了。第一步是理解 J MS 如何与 IBM 的标准 MQSeries 实现交互。MQSeries 的 Java 客户机能以两种模式之 一进行交互:客户机和绑定模式。只能通过 Java applet 来使用客户机模式,而绑定模 式取决于客户机上的 DLL 或者对象库。因为实现的特性,当使用用于 JMS 连接信息的 LDAP 服务器时,只能使用绑定模式。(不清楚为什么有这个限制,但它确实存在。) 因此,将用户登录和密码存储在一个全局位置(com.ibm.mq.MQEnvironment.class)而 不是在连接时传递它们。要解决这些供应商问题,我们创建了标准 JmsProvider 类(称 为 MQSeriesProvider)的子类。这个类将完成的唯一操作是覆盖如何创建连接。不象清 单 1 中那样 newQueueConnection = getConnectionFactory().createQueueConnection(getUserNam e(),getPassword)); 进行调用,我们必须调用 newQueueConnection = getConnectionFactory().createQueueConnection(); 最后,您需要将特定于 JMS 的元素(如队列、队列管理器、队列工厂等等)提供给客户 机。现在,使用 LDAP 和 JNDI 的原因就变得很明显:我们使用 LDAP 服务器来存储这 些元素并使用外部文件保存那些 LDAP 对象的键。LDAP 服务器可以作为 JNDI 服务器并 通过返回存储的对象来响应名称查询。这就是清单 2 中代码的工作原理。JMS 元素的名 称可从类的静态变量(对于缺省名称)或者外部文件(使用非缺省的其它名称)中获取 。简而言之,向 LDAP 服务器请求键(我们正讨论的)中存储的对象,并返回我们感兴 趣的 JMS 对象(在这种情况下)。 我们基于 JMS 的解决方案通过使用现有的组件更方便地实现统一的、跨平台和交叉供应 商的配置环境。现在我们的代码已尽可能地成为独立于特定于平台和特定于供应商的设 置。 应用程序 应用程序中有两个关键组件:发送器和接收器。发送器启动一个后台程序,它在目录中 轮询需要存档的文件,而接收器只是等待将要传递的 JMS 消息,然后将该消息中包含的 文件存档。JMS API 使我们几乎无需关注正使用的特定 JMS 实现就可以定义这些组件。 发送器由三个主要部件组成: JMSProvider,用于创建连接 ConnectionPool,用于获取现有的空闲连接(我们称之为 JMSConnection) 轮询程序,监视需要传送的文件。 在启动时,使用 JMSProvider 来创建一些到 JMS 服务器的准备就绪的连接。这些连接 放置在池中,然后启动轮询程序。当轮询程序检测到需要传送文件时,它就创建一个独 立线程来处理这个文件。(可以通过派生(forking),创建一个独立的线程来创建消息 和进行传送操作,描述该过程非常简单。但在实际应用中,常常将合用(pooling)与循 环组合起来使用,这样可以确保很少创建新线程,而是重用线程。但是,那个过程相当 复杂,过多的说明会分散本文的中心主题 ― JMS。) 在独立线程中,轮询程序接着从连接池中获取 JMSConnection,用它来创建一个 Bytes Message,并将这个文件的二进制内容放入那个消息中。最后这个消息查找到接收器,并 发送到 JMS 服务器,接着将 JMSConnection 返回给 ConnectionPool。这个发送过程的 部分步骤显示在下面的图 2 中。 图 2. 发送器过程 接收器是一个较简单的组件;它启动一些 FileListener 来等待将要放置在接收器队列 中的消息。下面的清单 4 中的代码显示了 FileListener 设置处理过程。图 6 中的类 实际上负责从队列中检索消息并对它们进行存档。JMS 保证队列发送每个消息的次数仅 一次,所以我们可以安全启动许多不同的 FileListener 线程并且知道每个消息(因此 每个文件)只处理一次。这个保证是使用基于 JMS 解决方案的另一个重要优点。在自己 设计的解决方案中开发这样的功能(比如基于 FTP 的功能),花销很大且易出错。 清单 4:来自类 ar.jms.file.receive.FileListener public void startOn(Queue qu eue) { setQueue(queue); createConnection(); try { createSession(); createReceiver(); getConnection().start(); // this starts the queue listener } catch (JMSException exception) { // Handle the exception } } public void createReceiver() throws javax.jms.JMSException { try { QueueReceiver receiver = getSession(). createReceiver(getQueue()); receiver.setMessageListener(this); } catch (JMSException exception) { // Handle the exception } } public void createSession() throws JMSException { setSession(getConnection(). createQueueSession(false, Session.AUTO_ACKNOWLEDGE)); } public void createConnection() { while (!hasConnection()) { try { setConnection(getClient().createConnection()); } catch (JMSException exception) { // Connections drop periodically on the internet, log and try again. try { Thread.sleep(2000); } catch (java.lang.InterruptedException ignored) { } } } } 以回调的方式编写消息处理代码,回调是当将消息传递给 FileListener 时,JMS 自动 调用的方法。这个消息的代码显示在下面的清单 5 中。 清单 5. 来自类 ar.jms.file.receive.FileListener public void onMessage(Messag e message) { BytesMessage byteMessage = ((BytesMessage) message); OutputStream stream = new BufferedOutputStream( new FileOutputStream(getFilenameFor(message))); byte[] buffer = new byte[getFileBufferSize()]; int length = 0; try { while ((length = byteMessage.readBytes(buffer)) != -1) { stream.write(buffer, 0, length); } stream.close(); } catch (JMSException exception) { // Handle the JMSException } catch (IOException exception) { // Handle the IOException } } 在设置接收器时要记住一条诀窍:在所有 FileListener 启动后,确保启动这些 FileL istener 的原始线程继续运行。这是必要的,因为某些 JMS 实现在守护程序的线程中启 动 QueueListener。所以,如果正在运行的唯一线程是守护程序的线程,那么 Java 虚 拟机(JVM)可能会过早地意外退出。下面的清单 6 显示了一些防止这种情况发生的简 单代码。 清单 6. 至少使一个非守护程序的线程保持运行 public static void main(String[] args) { ReceiverClient newReceiverClient = new ReceiverClient(); newReceiverClient.init(); setSoleInstance(newReceiverClient); while(!finished) { // This prevents the VM from exiting early try { Thread.sleep(1000); } catch (InterruptedException ex) { } } } 结束语 在该项目的最初实现之后,我们添加了一些功能,象消息压缩、当位置无法到达时的自 动恢复、联合消息代理、安全性、健壮的日志记录、管理等等。添加这些功能很容易, 因为 JMS 提供了开放模型,而且我们的体系结构也很健壮。构建整个系统花了六个星期 的时间,并且还很快地替换了客户一直使用的现有的、劳动密集型的系统。在这些天里 ,系统已经超出了所有的基准测试程序的标准并且已更正了原来系统遗留下来的错误。 这个项目不单超出了客户的期望,还证明了 JMS 是一个可行的解决方案,不仅适用于小 型、面向消息的应用程序,而且还适用于大规模的、重要任务的数据传送操作。 参考资料 获取更多信息或者下载 Qualcomm slapd。 访问 JMS 主页。 回顾 FTP 的安全性问题。 查阅 Giotta 等人编写的 JMS 设置一书:“Professional JMS Programming”。 学习有关 IBM MQSeries 的更多内容或者下载测试版本。 阅读 developerWorks 上的相关文章:“Java theory and practice: Should you use JMS in your next enterprise application?”。 阅读 developerWorks 上 Daniel 以前的文章:“The profound impact of hardware, software, and networking decisions”。 <淘宝热门商品:
 

35.00 元  

08新款泰迪熊出口日本 1米超大号 抱抱熊/趴趴

 

59.00 元 

doob多布-皇冠商铺机器猫一家现货供应


来源:程序员网

小小豆叮

JDK安装


 
Windows 98/ME: 简单的方法就是运行msconfig,这会显示一个实用程序,
在这里可以设置:
     设置项目如下:
       JAVA_HOME=L:\Java\J2SE     //你安装J2SE的目录
          //classpath设置,详见<>
       classpath=.;%JAVA_HOME%\lib\tools.jar;
       path=....;%JAVA_HOME%\bin;
  b)Windows 2000(我没XP,谁有,请跟贴):
        打开系统设置,按Winkey+Break 或 右击“我的电脑”,选属性
,选择高级->系统环境。
        在第一栏加入以下设置:
            JAVA_HOME=L:\Java\J2SE     //你安装J2SE的目录
             //classpath设置,详见<>
          classpath=.;%JAVA_HOME%\lib\tools.jar;
          path=......;%JAVA_HOME%\bin;
这就完成了J2SE 得安装。如果你想加入某个jar文件,可以从3个方面进行:
 1。系统设置。
 2。运行时设置参数。
 3。将你的jar文件拷贝到 %JAVA_HOME%\jre\lib\ext\ 里面。
    这里的jre是 java runtime environment。 可以在控制面版里设置。

Linux操作系统上安装的注意事项。
在安装JDK (Java Development Kit)或JRE (Java Runtime Environment)时,
这个Redhat package文件的默认安装路径是/usr/java。 
如果你要安装在其它路径下,例如要放到/usr/local/home 目录下,安装时
要敲的指令就是:  
rpm -i --badreloc --relocate /usr/java=/usr/local/home j2sdkj2sdk-
1_4_0-beta3-linux-i386.rpm 
如果安装在默认路径要敲的指令就是: 
rpm -ivh j2sdk-1_4_0-beta3-linux-i386.rpm 
然后设置/etc/profile  

# /etc/profile
# System wide environment and startup programs, for login setup
# Functions and aliases go in /etc/bashrc


# Path manipulation
JAVA_HOME=/usr/java/j2sdk1.4.0
CLASSPATH=/usr/java/j2sdk1.4.0/lib/tools.jar:/usr/java/j2sdk1.4.0
/lib/dt.jar:.:/root/myjava:/home/captain/myjava:/home/ocean/myjava
PATH=$PATH:$HOME/bin:.:/usr/java/j2sdk1.4.0/bin

if [ `id -u` = 0 ] && ! echo $PATH | /bin/grep -q "/sbin" ; then
   PATH=/sbin:$PATH
fi

if [ `id -u` = 0 ] && ! echo $PATH | /bin/grep -q "/usr/sbin" ; then
   PATH=/usr/sbin:$PATH
fi

if [ `id -u` = 0 ] && ! echo $PATH | /bin/grep -q "/usr/local/sbin" 
; then
   PATH=/usr/local/sbin:$PATH
fi

if ! echo $PATH | /bin/grep -q "/usr/X11R6/bin" ; then
   PATH="$PATH:/usr/X11R6/bin"
fi

# No core files by default
ulimit -S -c 0 > /dev/null 2>&1

USER=`id -un`
LOGNAME=$USER
MAIL="/var/spool/mail/$USER"

HOSTNAME=`/bin/hostname`
HISTSIZE=1000

if [ -z "$INPUTRC" -a ! -f "$HOME/.inputrc" ]; then
   INPUTRC=/etc/inputrc
fi

export PATH USER LOGNAME MAIL HOSTNAME HISTSIZE INPUTRC
export JAVA_HOME CLASSPATH

for i in /etc/profile.d/*.sh ; do
   if [ -r $i ]; then
   . $i
   fi
done

unset i
Export QT_XFT=1


<淘宝热门商品:
 

16.0元  

【珠三角商盟】联合利众●减肥瘦身●丰胸美乳●私处保养●美容

 

毛毛爱吃桔子  

毛毛爱吃桔子


来源:程序员网

小小豆叮