集成Java内容仓库和Spring.docx
- 文档编号:30009818
- 上传时间:2023-08-04
- 格式:DOCX
- 页数:11
- 大小:23.22KB
集成Java内容仓库和Spring.docx
《集成Java内容仓库和Spring.docx》由会员分享,可在线阅读,更多相关《集成Java内容仓库和Spring.docx(11页珍藏版)》请在冰豆网上搜索。
集成Java内容仓库和Spring
集成Java内容仓库和Spring
保存各种信息对于应用程序来说非常平常,大多数时候它们是保存在关系数据库中。
数据库处理规范数据类型十分在行,但是在处理如图像、文档等二进制数据时却不是那么得心应手。
尽管可以用文件系统作为替代——而且它们还提供了更好的性能。
但它们既没有提供用于搜索信息的查询语言,也没有提供表示关系或事务的概念。
在很多情况下,允许第三方访问这些存储数据(随着应用程序的不断扩展,这成为一个典型的需求)是一个漫长而复杂的过程(它们不会在一夜之间完成)。
内部存储结构很容易影响API架构,以及信息检索与遍历的方式。
什么是JSR-170
幸运的是,被称为Java内容仓库(JavaContentRepository,JCR)的JSR-170,试图以独立于具体实现的方式解决这些(以及其它)问题。
即,不论底层资源(如,数据库,本地或虚拟文件系统)是什么,API都将相同。
在数据存储之上,JCR提供诸如访问粒度控制、版本控制、内容事件、全文检索和过滤等内容服务。
由DaySoftware领导的JSR-170背后的专家组令人印象深刻,包括内容管理系统(CMS)提供商Vignette、HummingbirdLtd.、Stellent和通用Java驱动解决方案提供商,如BEASystems、IBM和Oracle。
该规范很可能成为内容管理和文档存储方面事实上的标准。
经过几乎2年半的努力,工作最终于2005年6月完成,在javax.jcr包中,API包含了大约50个类(主要是接口和异常)。
2006年早些时候,发布了初始1.0版本的参考实现(JackRabbit)。
JSR-170概览
Java内容仓库建立在仓库(除了是“用于安全地保存货物的地点”的通常含义之外)概念之上,它提供了几个操作数据的特性。
仓库使用“树结构”保存信息,如下图,树由节点和属性组成。
圆圈代表节点,方框代表属性。
1个节点有且只有1个父亲,有任意数目的孩子(子节点)和任意数目的属性。
1个属性有且只有一个父亲(它是节点),它没有子节点,由一个名字和一个或多个值组成。
属性值的类型可以是:
布尔(Boolean)、日期(Date)、双精(Double),长整(Long),字符串(String)或流(Stream)。
只有属性可以被用来存储信息,节点则被用来创建树内部的“路径”。
在某种程度上,这棵树类似文件系统的结构,节点是目录,属性是实际的文件。
仓库的功能被划分为几个“兼容性”级别,每个级别提供一组特定的特性:
级别1对于所有实现,级别1是必须的,它提供对仓库的读访问,简而言之:
对节点和属性的读访问。
对属性值的读访问。
输出到XML/SAX。
支持XPATH语法的查询服务。
级别2级别2提供写功能:
增加和移除节点和属性。
对属性值的写操作。
从XML/SAX输入数据。
值得注意的是,JCR的实现并不要求达到级别2或者更高层次。
因此与只读仓库一起工作也是完全符合规范的。
可选级别“可选”级别包含一些高级特性,它并不是读写仓库所必需的,但确是真正为JSR-170增色的部分。
这个级别包括(除了其它之外):
事务——它使仓库有可能与JMS或JDBC资源一起工作。
版本标定——允许仓库记录节点的不同状态,以备日后检索。
规范对于这个主题有相当的篇幅;该特性使得用JSR-170作为后端构建一个CVS的克隆成为可能。
事件——亦称观察,它允许仓库内发生的任何活动都会被通知给客户端。
锁——可以冻结部分树的功能,它可以有效地返回一个只读的子树。
API回顾
使用JSR-170时,建议使用来自javax.jcr包的接口。
这样,更换JCR实现时会容易些,不会有任何代码的变动。
API的核心类是Session,它代表客户端和仓库之间的连接,使用连接活跃其上的workspace名和所提供的credentials进行定义。
Session包含读(级别1)和写(级别2)方法;使用底层仓库不支持的功能时将抛出异常。
这个包还包含了那些组成仓库的单元接口的定义:
Workspace,Credentials,Node,Property,Item(Node和Property的超类)和Value。
javax.jcr.query包负责处理查询,javax.jcr.nodetype包负责定义节点类型。
剩余的包负责可选级别的功能,如javax.jcr.version、javax.jcr.observation、javax.jcr.lock。
一个有趣的包是javax.jcr.util,它包含一个ItemVisitor的实现,它源自GOF(四人帮,GangofFour)撰写的著名的设计模式中的访问者模式(Visitor-pattern)接口。
JSR-170实现
Google和SourceForge会列出好几页的JSR-170实现,但是它们中的大多数都处于alpha阶段,没有发布任何版本。
以下是一个可以自由下载的项目列表,它们已经被作者使用过:
Jackrabbit它是JSR-170的参考实现,Apache基金的一部分,提供级别1,2和可选功能。
在撰写本文时,它已经经过孵化阶段并有一个官方公开的发布版本,该版本被认为足够稳定,可以被用在产品环境。
此外,Jackrabbit也被用来作为DaySoftware(JSR-170的领导者)的商业产品的基础。
除了实现JSR-170中定义的所有特性,JackRabbit还加入了额外的功能(如SessionListeners或CustomNode注册),以及一个有趣的捐献来的项目套件,它包括:
JCA连接器、taglib、WebDAV接口、虚拟文件系统和JDBC后端。
JackRabbit的许可证是Apache2.0。
eXoJCR它是eXoplatoform的一部分,包含规范要求的所有强制特性和几个可选特性。
最近一次的版本发布(1.0RC7)是2006年6月22日,基于规范的最终草案2。
eXoJCR支持JDBC兼容数据库,如MySQL、DB2或HSQL(它是缺省的)作为后端存储,它是双许可的(GPL和商用),最终版的发布日期尚未确定。
Jeceira与Jackrabbit和eXoJCR相比,它是相对较新的项目。
它实现了级别1和2的一些需求,只在写操作时,支持来自可选级别的观察功能。
不幸的是,这个项目处于未完成阶段,在过去的9个月没有新版本发布。
然而它被Magnolia(一个流行的基于java的CMS,与作为JSR-170参考实现的Jackrabbit类似)使用。
在最终版发布时,它计划包含所有级别的功能,发布时间目前尚不确定。
Jeceira的许可证是Apache2.0,使用HSQL数据库作为它的存储引擎。
JCR模块
SpringModules的一部分,JCR模块的主要目标是:
以一种类似Spring主分发包中ORM包的方式,简化使用JSR-170API进行开发。
特点如下:
JcrTemplate,允许执行JcrCallback和异常处理(将需检查的JCR异常转换成不需检查的SpringDAO异常)。
这个模板实现了来自JCRSession的绝大部分方法,可以简单地作为替换物使用。
此外该模板知道线程绑定的会话,这个会话可以跨几个方法使用,这在使用事务型仓库时非常有用。
RepositoryFactoryBean,它配置、启动和停止仓库实例。
因为JSR-170并没有说明仓库配置的标准方式,需要注意实现在这个方面的不同。
这个支持包含预定义的用于Jackrabbit和Jeceira的FactoryBean,以及一个可以很容易支持其它仓库的抽象基类。
SessionFactory,用来统一Repository,Credentials和Workspace接口,允许自动注册监听器和自定义名字空间。
Spring声明性事务为那些实现了(可选)事务特性的仓库提供了支持。
OpenSessionInView拦截器和过滤器允许每个线程跨不同组件使用同一会话。
与JcrTemplate一起,检索、关闭和管理JCR会话的工作已经外部化,对于调用者完全透明。
本文将使用参考实现(Jackrabbit),由于JCR模块使用的是javax.jcr接口,因此改变实现根本就是一个配置的问题。
让我们一步一步地来看看在Jackrabbit之上如何使用Java内容仓库,以及如何让Spring模块来帮助完成这一工作。
配置仓库和SessionFactory
--normalfactorybeansparams-->
jackrabbit-repo.xml"/> JCR支持提供RepositoryFactoryBean类配置Jackrabbit,它需要JackRabbit的配置文件和主目录。 注意,RepositoryFactoryBean在使用本地文件系统时特别有用;对于服务器环境,仓库可能被注册在JNDI中,此时可以使用JndiObjectFactoryBean帮助类(Spring分发包的一部分)检索它: comp/env/jcr/myRepository"/> 或使用Spring2.0的模式名字空间: lookupid="entityManagerFactory"jndi-name="jcr/myRepository"/> 为了简化与JCR的工作,模块增加了SessionFactory接口: publicinterfaceSessionFactory{ publicSessiongetSession()throwsRepositoryException; publicSessionHoldergetSessionHolder(Sessionsession); } SessionFactory隐藏了实现内部的认证细节,因此一旦配置完成,使用同一证书的会话可以很容易的被检索出来。 为了利用实现的特性(没有涵盖在规范中的),这个接口允许检索SessionHolder。 它是一个JCR模块特定类,主要被用于事务和会话管理(通过一种可用于每个JCR实现的缺省、通用实现),但是它不支持可选特性或自定义特性(如JackrabbitSessionHolder,它支持Jackrabbit的事务基础结构)。 JCR模块提供一种简易、透明的方式来发现SessionHolder实现(这些我将在以后详细提到),使之很容易地插入对JSR-170其它兼容库的支持。 SessionFactory的缺省实现是JcrSessionFactory,它要求一个进行工作的仓库和证书。 -—SessionFactory--> --createthecredentialsusingabeanfactory--> --createthepasswordtoreturnitasachar[]--> 这个bean声明非常简单,唯一需要注意的地方是,密码被提供给SimpleCredential的构造函数: 它只接受字符数组,使用Spring工厂声明作为一种变通。 JcrTemplate JcrTemplate是JCR模块的核心类之一,它提供了与JCR会话一起工作的方便方法,将调用者从必须处理的打开和关闭会话、事务回滚(如果底层仓库提供)、以及处理其它特性中的异常等工作中解放出来: 模板定义非常简单,类似来自Spring框架的其它模板类,如HibernateTemplate。 例子 既然仓库已经配置了,接下来看看“Spring化”的例子之一,它来自Jackrabbit的wiki页: publicNodeimportFile(finalNodefolderNode,finalFilefile,finalStringmimeType,finalStringencoding){ return(Node)execute(newJcrCallback(){/***@seeorg.springmodules.jcr.JcrCallback#doInJcr(javax.jcr.Session)*/ publicObjectdoInJcr(Sessionsession)throwsRepositoryException,IOException{ JcrConstantsjcrConstants=newJcrConstants(session); //createthefilenode-seesection6.7.22.6ofthespecNodefileNode=folderNode.addNode(file.getName(),jcrConstants.getNT_FILE());//createthemandatorychildnode-jcr: contentNoderesNode=fileNode.addNode(jcrConstants.getJCR_CONTENT(),jcrConstants.getNT_RESOURCE()); resNode.setProperty(jcrConstants.getJCR_MIMETYPE(),mimeType);resNode.setProperty(jcrConstants.getJCR_ENCODING(),encoding); resNode.setProperty(jcrConstants.getJCR_DATA(),newFileInputStream(file)); CalendarlastModified=Calendar.getInstance(); lastModified.setTimeInMillis(file.lastModified());resNode.setProperty(jcrConstants.getJCR_LASTMODIFIED(),lastModified); session.save();returnresNode; } }); } 主要区别是: 代码被包装在一个JCR模板中,它将我们从不得不使用的try/catch语句块(因为IO和Repository的需检查异常)和处理会话(和事务,如果有的话)清除工作中解放出来。 值得提及的是硬编码字符串,如“jcr: data”,是通过JcrConstants工具类解析出来的。 它知道名字空间的前缀变化,并提供一种干净的方式处理JCR常数。 正如你看到的,我只是使例子更加健壮,但是对于实际业务代码影响最小。 事务支持 使用JCR模块的一个好处就是能将Spring事务基础设施(包括声明性和编程性)应用于Java内容仓库。 JSR170将事务支持视为可选特性,并没有强制一个标准的方式来暴露事务钩子,因此每个实现可以选择不同的方法。 在本文撰写时,只有Jackrabbit支持事务(在它的大部分操作中),它通过为每个JcrSession暴露一个javax.transaction.XAResource做到这一点。 JCR模块提供LocalTransactionManager用于本地事务: 为了声明事务划分,我与上述事务管理器bean声明一起使用标准Spring类: --transactionproxyforJcrservices/facades--> 如果要求一个JTA管理器,一个简单而优雅的解决办法是使用来自Jackrabbit捐献包的jca连接器。 为了使用jca,你并不需要一个应用服务器,因为你可以用一个可插入的JCA容器,如Jencks。 JCA容器的配置已经超出本文的范围,但是你可以参考JCR模块例子中使用Jencks的例子。 TransactionAwareRepository 对于要求普通JCR代码的应用程序,JCR模块允许用直接使用JCRAPI的代码,透明地使用事务驱动会话。 此时,可以使用TransactionAwareRepository,它有一个参数是JcrSessionFactory。 这样,在使用Session.login()(它接收定义在JcrSessionFactory中的参数)创建任何新会话时,如果发现有线程绑定的会话,就将返回它。 注意: 如果使用事务,JCR会话就是事务性的,否则你必须手动设置属性allowNonTxRepository为true,配置如下,要不然将抛出一个异常: transactionRepositorybean可以被用作一个普通的JCR仓库,不关心底层机制或线程绑定会话、事务性或非事务性(如果有事务,关闭会话时要提交事务)。 可选特性支持侦测 为了最大化代码重用,但仍然允许插入可选特性,如用于不同JCR实现的事务支持,JCR模块使用SessionHolder接口(前面已经提到),同时还有SessionHolderProvider和SessionHolderProviderManager接口。 用户一般不用与它们打交道,因为它们是框架内部使用的;但是,它们代表了JCR模块主要的扩展点。 SessionHolder类被内部不同组件使用,主要被事务管理器用来操作会话,SessionHolderProvider和SessionHolderProviderManager处理sessionHolder创建的方式以及提供者是如何被个别使用的。 缺省将使用ServiceSessionHolderProviderManager,它利用JDK1.3ServiceProvider的自动发现特性。 管理器将在类路径中搜索META-INF/services/org.springmodules.jcr.SessionHolderProvider条目,它包含了SessionHolderProvider实现的完整限定名。 Jackrabbit支持就是这样配置的,JCR模块的分发包中包含一个META-INF/services/org.springmodules.jcr.SessionHolderProvider(译注: 原文有误,没有给出后面的文件名)文件,它只有一行: org.springmodules.jcr.jackrabbit.support.JackRabbitSessionHolderProvider 缺省,SessionHolderProviderManager被JcrSessionFactory内部使用,因此在工厂启动时,任何客户化实现可以被获取,并与合适的仓库一起使用。 但是,通过设置JcrSessionFactory中的SessionHolderProviderManager,可以很容易的切换到一个不同的发现策略。 一个可替代的发现服务是ListS
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 集成 Java 内容 仓库 Spring
![提示](https://static.bdocx.com/images/bang_tan.gif)