刘文涛

Flex3,Struts2,Hibernate3,Spring2,UML,Oracle,mysql,tomcat,compass,lucene

   :: 首页 ::  ::  ::  :: 管理 ::

2006年8月17日 #

一、概述

在Web应用中,有些报表的生成可能需要数据库花很长时间才能计算出来;有的网站提供天气信息,它需要访问远程服务器进行SOAP调用才能得到温度信息。所有这一切都属于复杂信息的例子。在Web页面中加入过多的复杂信息可能导致Web服务器、数据库服务器负荷过重。JSP代码块缓冲为开发者带来了随意地增加各种复杂信息的自由。

JSP能够在标记库内封装和运行复杂的Java代码,它使得JSP页面文件更容易维护,使得非专业开发人员使用JSP页面文件更加方便。现在已经有许多标记库,它们或者是商业产品,或者是源代码开放产品。但这些产品中的大多数都只是用标记库的形式实现原本可以用一个简单的Java Scriptlet实现的功能,很少有产品以某种创造性的方式使用定制标记,提供在出现JSP定制标记库之前几乎不可能实现的用法。

OSCache标记库由OpenSymphony设计,它是一种开创性的JSP定制标记应用,提供了在现有JSP页面之内实现快速内存缓冲的功能。虽然已经有一些供应商在提供各种形式的缓存产品,但是,它们都属于面向特定供应商的产品。OSCache能够在任何JSP 1.1兼容的服务器上运行,它不仅能够为所有用户缓冲现有JSP代码块,而且能够以用户为单位进行缓冲。OSCache还包含一些提高可伸缩性的高级特性,比如:缓冲到磁盘,可编程的缓冲刷新,异常控制,等等。另外,正如OpenSymphony的其他产品,OSCache的代码也在一个开放源代码许可协议之下免费发行。

本文以一个假想的拍卖网站设计过程为例,介绍OSCache的工作过程。这个假想的Web网站将包含:

1 :一个报告最近拍卖活动的管理页面;
2 :一个功能完整、带有各种宣传信息的主页;
3 :一个特殊的导航条,包含了用户所有尚未成交的拍卖活动信息。

二、管理页面

拍卖网站包含一个管理报表,数据库服务器需要数秒时间才能创建这样一个报表。报表生成时间长这一点很重要,因为我们可能让多个管理员监视系统运行情况,同时又想避免管理员每次访问时都重新生成这个报表。为了实现这一点,我们将把整个页面封装到一个应用级的缓冲标记之内,这个缓冲标记每隔1小时刷新。其他供应商提供的一些产品也具有类似的功能,只是OSCache比它们做得更好。

为简单计,我们将不过多地关注格式问题。在编写管理页面时,我们首先把标记库声明加入到页面:

<%@ taglib uri="cachetags" prefix="cache" %>

接下来我们要用cache标记来包围整个页面。cache标记的默认缓冲时间是1小时。

<cache:cache> .... 复杂的管理报表 .... </cache:cache>

现在管理页面已经被缓冲。如果管理员在页面生成后的一个小时之内再次访问同一页面,他看到的将是以前缓存的页面,不需要由数据库服务器再次生成这个报表。

三、主页

拍卖网站的主页显示网站活动情况,宣传那些即将结束的拍卖活动。我们希望显示出正在进行的拍卖活动数量,当前登录用户数量,在短期内就要结束的拍卖活动的清单,以及当前时间。这些信息有着不同的时间精确度要求。网站上的拍卖活动通常持续数天,因此我们可以把缓冲有效拍卖活动数量的时间定为6个小时。用户数量的变化显然要频繁一些,但这里我们将把这个数值每次缓冲15分钟。最后,我们希望页面中显示的当前时间总是精确的页面访问时间。

在主页中声明标记库之后,我们首先以不带缓冲的方式直接输出当前日期:

现在是:<%=new java.util.Date()%>

接下来,我们要显示一个清单,列出那些将在短期内结束的拍卖活动:

<cache:cache> <ul> <% // 构造一个包含最近拍卖活动的Iterator Iterator auctions = .... while (auctions.hasMore()) { Auction auction = (Auction)auctions.next(); %><li><%=auction%></li%< } %> </ul> </cache:cache>

最后,我们希望显示出正在进行的拍卖活动的数量,这个数字需要缓冲6小时。由于cache标记需要的是缓冲数据的秒数,我们把6小时转换成21600秒:

<cache:cache time="21600"> <% //查询数据库得到拍卖活动总数 int auctionCount = .... %> 本网站正在进行的拍卖活动有<%=auctionCount%>个! </cache>

可以看到,我们只用少量的代码就构造出了一个带有复杂缓冲系统的主页。这个缓冲系统对页面各个部分分别进行缓冲,而且各个部分的缓冲时间完全符合它们各自的信息变化频繁程度。由于有了缓冲,现在我们可以在主页中放入更多的内容;而在以前没有缓冲的情况下,主页中放入过多的内容会导致页面访问速度变慢,甚至可能给数据库服务器带来过重的负载。

四、导航条

假设在规划网站的时候,我们决定在左边导航条的下方显示购物车内容。我们将显示出用户所拍卖的每一种商品的出价次数和当前报价,以及所有那些当前用户出价最高的商品的清单。

我们利用会话级的缓冲能力在导航条中构造上述功能。把下面的代码放入模板或者包含文件,以便网站中的其他页面引用这个导航条:

<cache:cache key="navbar" scope="session" time="300"> <% //提取并显示当前的出价信息 %> </cache:cache>

在这里我们引入了两个重要的属性,即key和scope。在本文前面的代码中,由于cache标记能够自动为代码块创建唯一的key,所以我们不需要手工设置这个key属性。但在这里,我们想要从网站的其余部分引用这个被缓冲的代码块,因此我们显式定义了该cache标记的key属性。第二,scope属性用来告诉cache标记当前代码块必须以用户为单位缓冲,而不是为所有用户缓冲一次。

在使用会话级缓冲时应该非常小心,应该清楚:虽然我们可以让复杂的导航条减少5倍或10倍的服务器负载,但它将极大地增加每个会话所需要的内存空间 。在CPU能力方面增加可能的并发用户数量无疑很理想,但是,一旦在内存支持能力方面让并发用户数量降低到了CPU的限制之下,这个方案就不再理想。

正如本文前面所提到的,我们希望从网站的其余部分引用这个缓冲的代码块。这是因为,当一个用户增加了一个供拍卖的商品、或者出价竞购其他用户拍卖的商品时,我们希望刷新缓冲,使得导航条下一次被读取时具有最新的内容。虽然这些数据可能因为其他用户的活动而改变,但如果用户在网站上执行某个动作之后看到自己的清单仍未改变,他可能会感到非常困惑。

OSCache库提供的flush标记能够刷新缓冲内容。我们可以把下面的代码加入到处理用户动作且可能影响这一区域的页面之中:

<cache:flush key="navbar" scope="session" />

当用户下次访问它时,navbar缓冲块将被刷新。

至此为止,我们这个示例网站的构造工作已经完成且可以开始运行。下面我们来看看OSCache的异常处理能力。即使缓冲的内容已经作废,比如在缓冲块内出现了Java异常,OSCache标记库仍旧允许我们用编程的方法显示这些内容。有了这种异常控制功能,我们可以拆除数据库服务器和Web服务器之间的连接,而网站仍能够继续运行。JSP 1.2规范引入了TryCatchFinally接口,这个接口允许标记本身检测和处理Java异常。因此,标记可以结合这种异常处理代码,使得JSP页面更简单、更富有条理。

OpenSymphony正在计划实现其他的缓冲机制以及一个可管理性更好的主系统,它将使我们能够对缓冲使用的RAM和磁盘空间进行管理。一旦有了这些功能,我们就能够进一步提高网站的响应速度和可靠性。

使用范例:

oscache.properties 文件配置向导

cache.memory
值为true 或 false ,默认为在内存中作缓存,
如设置为false,那cache只能缓存到数据库或硬盘中,那cache还有什么意义:)

cache.capacity
缓存元素个数

cache.persistence.class
持久化缓存类,如此类打开,则必须设置cache.path信息

cache.cluster 相关
为集群设置信息。

cache.cluster.multicast.ip为广播IP地址
cache.cluster.properties为集群属性


3.OSCache的基本用法

cache1.jsp 内容如下

<%@ page import="java.util.*" %>
<%@ taglib uri="oscache" prefix="cache" %>

<html>
<body>

没有缓存的日期: <%= new Date() %><p>
<!--自动刷新-->
<cache:cache time="30">
每30秒刷新缓存一次的日期: <%= new Date() %>
</cache:cache>
<!--手动刷新-->
<cache:cache key="testcache">
手动刷新缓存的日期: <%= new Date() %> <p>
</cache:cache>
<a href="/cache2.jsp">手动刷新</a>

</body>
</html>

cache2.jsp 执行手动刷新页面如下
<%@ taglib uri="oscache" prefix="cache" %>

<html>
<body>

缓存已刷新...<p>

<cache:flush key="testcache" scope="application"/>

<a href="/cache1.jsp">返回</a>

</body>
</html>


你也可以通过下面语句定义Cache的有效范围,如不定义scope,scope默认为Applcation
<cache:cache time="30" scope="session">
...
</cache:cache>

4. 缓存过滤器 CacheFilter

你可以在web.xml中定义缓存过滤器,定义特定资源的缓存。

 1 < filter >
 2      < filter - name > CacheFilter </ filter - name >
 3      < filter - class > com.opensymphony.oscache.web.filter.CacheFilter </ filter - class >
 4      < init - param >
 5          < param - name > time </ param - name >
 6          < param - value > 60 </ param - value >
 7      </ init - param >
 8      < init - param >
 9          < param - name > scope </ param - name >
10          < param - value > session </ param - value >
11      </ init - param >
12 </ filter >
13
14
15 < filter - mapping >
16      < filter - name > CacheFilter </ filter - name >
17      < url - pattern >* .jsp </ url - pattern >
18 </ filter - mapping >

上面定义将缓存所有.jsp页面,缓存刷新时间为60秒,缓存作用域为Session

注意,CacheFilter只捕获Http头为200的页面请求,即只对无错误请求作缓存,
而不对其他请求(如500,404,400)作缓存处理

【结束语】OSCache能够帮助我们构造出更丰富多彩、具有更高性能的网站。有了OSCache标记库的帮助,现在我们能够用它解决一些影响网站响应能力的问题,比如访问量高峰期、数据库服务器负荷过重等。

个人提示:如果你使用Struts或者其它mvc架构很难享受到oscache tag带来的性能提高,因为每一次请求还是要提交到action--dao-or othere thing去处理,因此,要使用缓存,就需要其它手段,如在spring的拦截器做方法级的缓存.....,如果你所有的的业务处理代码是写在jsp页面中,就可以使用cache tag来缓存前面产生的页面数据,避免做相同的业务操作.

 

posted @ 2006-08-17 19:14 刘文涛| 编辑 收藏

AppFuse是一个集成了当前最流行的Web应用框架的一个更高层次的Web开发框架,
也可以说是一个Web开发基础平台,它与它所集成的各种框架相比,它提供了一部分所有Web系统开发过程中都需要开发的一些功能,如 :

11:登陆、
22:用户密码加密
33:用户管理
44:根据不同的用户可以展现不同的菜单


1a:可以自动生成40%-60%左右的代码
2b:自带了默认的一些在CSS中设定的样式,使用这些样式能很快的改变整个系统的外观
3c:有自动化测试的功能
 

它最大的价值就是为我们提供了一个Web开发的新的方式和思路,尽管这些技术在国外都已进很流行了,但在国内能够将

 1Hibernate
 2Struts
 3Spring
 4DBUnit
 5Ant
 6Log4J
 7Struts Menu
 8Xdoclet
 9SiteMesh
10Velocity
11JUnit
12JSTL
13WebWork

这些技术集成到一个框架中的还不多见,所以即使不使用它的全部功能,它也给我们提供了一个很好的借鉴、学习的机会。通过关注AppFuse,我们可以看到目前国外的主流开发都使用了哪些技术,开发方式是什么样的,可能达到什么样的结果,而在以前,是很少能够看到这样完整的例子的。

AppFuse的另一个启示是:我们可以依靠开源软件的功能降低开发成本,而且可以阅读开源软件的代码提高所在团队的整体实力。

AppFuse的作者 matt raible是当今开源世界一个比较活跃的开发者,它是AppFuse、Struts Menu的作者,也是XDoclet、DisplayTag等一些著名开源项目的积极参与者,《Hibernate In Action》的作者就在感谢的名单里面提到他,XDoclet的下载版本中所带的Hibernate标签部分的例子就是他写的,他还是2004年Apache技术年会的主讲人之一。(这些都是我这2个多月来搜集到的,呵呵)

但是通过2个月的实际学习和使用,我也遇到一系列的问题,因为AppFuse是将其他的一些类库或者框架集成在一起的,集成的技术众多,而且有一些技术在国内甚至很少有人知道,资料也比较少,所以虽然作者经过了一些测试,但都是基于英文编码的,而对于中文编码来说,还潜在的存在着一些问题,虽然不是AppFuse的问题,但却降低了开发速度,下面是我在开发过程中遇到过的问题,有些解决了,有些还没有解决:
 
一.Struts
1. AppFuse中默认的MVC框架是Struts,而且使用的是LookupDispatchAction,并且使用的是按钮(button),在XP下用IE浏览效果还可以,但如果在2000或者98下,就使外观很难看,而且当时我还遇到一个问题:如果按钮显示中文,则在DisplayTag中翻页失灵,而且报错,后来我把BaseAction的相关方法改变了,才可以使用,因为国内的客户都比较重视界面,所以后来我将那些按钮都改成图片了,当然也要添加一些方法了,有点麻烦!

2. Struts中的标签如今推荐使用的只有html部分的标签了,其他的标签或者可以使用JSTL替代,或者已经不推荐使用了,而且AppFuse中推荐使用JSTL,而JSTL和struts的标签的联合使用时,需要的不是<标签>,而是<标签>,这个问题曾经困扰了我整整2天。

3. Struts的Validation的校验规则并不完善,比如如果使用客户端的javascript校验,则在邮箱中输入汉字根本校验不出来,到了服务器端报错。
 
4. 最严重的问题是AppFuse生成的Struts的validation.xml文件中有许多多余的“.”,如果你去掉了,常常在执行ant的deploy任务时又恢复原样。这样是提交表单的时候经常会报javascript的脚本错误或者缺少对象或者缺少value,所以我会手工的修改这个文件,然后把修改后的文件备份,当重新生成有错误的文件时,我会用备份的没有错误的文件去覆盖。
5. Struts的validatioin对于使用同一个FormBean的Action的校验方式比较复杂。(待解决)。

二.Hibernate
1. Hibernate是现在受到越来越多的人推崇的一个ORM工具(框架、类库),它将我们从繁琐的使用JDBC的开发过程中解放出来,但同时也带来了新的问题,如学习曲线,执行效率,数据库设计优化,还有最重要的灵活性。Hibernate不是一个很容易上手的东西,要完全驾驭它还需要读很多资料,但好的资料却很少。
 
2. 使用Xdoclet可以很方便的生成Hibernate中的持久类的配置文件(*.hbm.xml),但对一些特殊的映射却无能为力,如使用序列的id生成规则,序列的名字没有地方写,所以也只好先利用它生成主要的内容,然后手工修改。
 
3. 同样还是id的生成策略问题,如果使用序列、hilo等需要一些数据库机制支持的策略时,schemaExport并不能自动生成序列或者保存当前id的表,这项工作仍然要手工解决。
 
4. Hibernate中提供了几种关联,一对一、一对多、多对多,但对于怎样调整效率却没有一个很明确的提示,还要根据情况判定,这就带来和一些弹性的设计。
 
5. Hibernate中可以选择的操作数据库的方式有3种,其中HQL功能最强大,但有些功能使用标准查询可能会更方便,但会有一些限制,所以虽然它很灵活,但易用性不如JDBC好。

三.Spring
在AppFuse的过程中,Spring完全隐藏在幕后,除了一些配置外,几乎感觉不到它的存在,所以我在使用它的过程中并没有遇到什么麻烦,这里只是简单的介绍一下它在AppFuse中起到的作用。
 
1. Spring在AppFuse中起到的主要作用是对Hibernate的Session事务的管理,利用Spring封装的Hibernate模板类,我们大大地减少了实现DAO的代码行数。

2. Spring还起到了连接映射文件和类之间的关联,及接口和实现类之间的关联,这些都依赖于Spring的IoC的机制的实现。

3. 对于字符进行编码和解码部分用到了Spring自带的Filter,只需要在配置文件中配置就好了。

四.SiteMesh
SiteMesh是一个基于Decorator模式的技术,它可以修饰返回的网页文件,它的工作方式受到越来越多的人的推崇,这点从Manning出版的一些技术书籍中可以看出来。
我在使用SiteMesh的过程中并不顺利,我参考了《Java Open Source Programming》,这本书中说SiteMesh在默认的情况下不对下载文件进行装饰,但我在下载文件时发现,我的文件内容被丢弃了,取而代之的是SiteMesh的模板的内容,后来我通过修改SiteMesh的配置文件解决了这个问题,但感觉还有一些不太清楚的地方需要学习。

五.DisplayTag
DisplayTag是一个优秀的显示内容的标签,从SourceForge的访问量来看,它是很活跃的项目,仅次于Ant、Hibernate、Xdoclet等几个著名的项目,我总结,它的主要功能有4项:显示、分页、排序、将显示的数据写入指定类型的文件中,然后下载。
1. 据我使用的情况看,我只使用了分页和显示的功能,因为当时我没有很好的解决中文编码的问题,所以排序会有问题,直到昨天,我在朋友的帮助下解决了这个问题,至此我可以放心使用的功能又增加了排序(我昨天简单的测试了一下是可以的)。

2. 但对于将显示的内容生成到一个指定格式的文件中的功能却有着很多缺陷,如:
(1) 生成的文件中只有显示的数据,那些没有显示在界面上的的数据,则不会被写到文件中。
(2) 如果修改了DisplayTag的显示的内容,比如添加一列,在这列中的内容不是字符,而是HTML的标签,则生成的文件只有这些HTML标签,而没有数据。
(3) 即使DisplayTag中没有我们定制的HTML脚本,生成的文件偶尔也有问题,比如:它会把“007”生成为“7”,把字符串自动的转换为整型值。有时候还生成空白内容的文件。
(4) DisplayTag生成的Excel文件兼容性不好,有时在Excel2003中不能正常打开,或者在XP下打开报错。
后来,我看了作者写的《Spring Live》,书中说如果想实现稳定的Excel,推荐使用POI,于是我使用POI生成Excel,稳定性和兼容性都不错。

六.DBUnit
DBUnit是一个可以被Ant集成的向数据库中添加数据和备份数据的一个类库,配置很方便,因为AppFuse已经集成好了,所以使用也很容易。但是如果你使用EditPlus之类的工具手工修改了AppFuse生成的内容,则执行Ant的setup、setup-db或者deploy的任务时,常常报错,说无效的格式,这是因为这个被手工修改的文件再次被AppFuse执行后,它的第一行的文件声明的前几个字母是无效的,是因为本地的字符集编码的原因而引起了乱码,如果把这几个无效的字母去掉,问题就解决了。

七.Struts Menu
Struts Menu也是AppFuse的作者开发的一个开源软件,它可以根据配置文件读取当前用户可以使用的功能菜单,这个功能是我一直以来都想要的,我也找到了一些代码,但实现的都不如这个完善,没什么好说的,使用简单,配置容易,很好的解决了我的问题。问题是我只使用了AppFuse提供的2个角色,对于多个角色的实验我还没有做。

八.XDoclet
在AppFuse中,使用Xdoclet生成了几乎一切的配置文件:

1Struts-config.xml
2web.xml
3validation.xml
4*.hbm.xml

等文件,如果使用AppGen的话,还会生成更多的文件,这一切都是使用Xdoclet实现的。
问题是我在Struts部分提到的,生成的Validation.xml文件中会多生成一个“.”,另外在生成资源文件时也会多生成一个“.”,目前我没有很好的阅读这段代码,不知道是不是Xdoclet的问题。

九.Ant
Ant并没有什么问题,但在执行作者写的Ant任务的时候,有一些任务不能正常执行,比如,运行模拟对象测试的任务,作者也在1.7版本的修复列表中提到以前版本有些ant任务不能执行,在1.7中修改了一些ant任务,使他们能够正常的执行了。实际上,我们如果使用AppGen进行开发的话,使用的任务一般不超过8个。

十.JSTL
JSTL是个好东西,我常用的有和部分的标签,但是如果使用JSTL进行逻辑判断,我并没有感觉比使用JSP的代码块优雅多少。另外,熟悉JSTL也需要一段时间,我就经历了面对着JSP页面不知道该怎么写JSTL语法的困境。当然,AppFuse中使用的基本都是JSTL,包括向DisplayTag传递显示的数据,使用的都是JSTL语法,这方面的资料挺多,我参考的是电子工业出版社出的《JSP2.0技术》,说的很详细。

十一.Tomcat
你也许会说:“Tomcat就不用说了吧?”,是的,Tomcat一般都会使用,但是Tomcat5和Tomcat4.X对于中文编码使用了不同的机制,这个问题困扰了我好久,我解决了页面上写入汉字显示乱码的问题,我也曾经以为DisplayTag对汉字不能排序,也不能正常分页是因为DisplayTag的开发者都是老外,是因为他们没有考虑中文的关系的原因。
直到昨天,我才知道这一切都是因为Tomcat5对汉字编码的实现的方式和Tomcat4不一样的原因,如果感兴趣,可以看看这个帖子:http://www.javaworld.com.tw/jute/post/view?bid=9&id=44042&sty=1&tpg=1&age=0

十二.JavaScript
JavaScript简单易学,但想运用自如就不太容易了。AppFuse中嵌入了几个js文件,里面包含了许多函数,值得我们好好的研究一下,比如,如果有一个必填字段没有填写,AppFuse会自动的聚焦在那个input上,类似的小技巧有很多,你可以自己去翻看。但AppFuse自带的JavaScript脚本有一个Bug,就是当DisplatyTag中没有可以显示的数据时,你用鼠标单击,它会报JavaScript错误,你仔细研究一下function highlightTableRows(tableId) 就知道了:我的解决办法是在location.href = link.getAttribute("href");前面添加一行判断:if (link != null)。

十三.资源文件国际化
对于Struts和DisplayTag都涉及到资源文件国际化AppFuse1.6.1很好的解决了Struts资源映射文件国际化的问题,你只需要在对应本国语言的资源文件中写入汉字,Ant中有一项执行native2ascii的任务,AppFuse自动的为你进行了资源文件的编码转换,而对于DisplayTag的资源文件问题,还要自己执行native2ascii命令,为了避免每次都输入一串命令,我用Delphi写了个小工具,可视化的选择资源文件,点击按钮自动执行该命令,底层依赖于JDK。


经过2个多月的学习,我感觉这个框架非常不错,它为我以后的项目开发指出了一个新的方向,但如果想很熟练的使用这个框架进行开发,至少要对以下几种技术比较熟练:Struts(或者WebWork、Spring及其他的已经整合进来的MVC框架)、Hibernate(或者ibatis)、JSTL,当然其他的技术至少也要知道一点,否则遇到问题都不知道出在哪里。


目前我还没有解决的问题有:
1. 如何在翻页的时候才读取下面的数据?
2. 怎样对使用同一个FormBean的多个Form进行客户端校验?
3. 怎样优化Hibernate的效率?《Hibernate In Action》中提供了多种策略,有些时候应该使用lazy,有些时候应该使用outer-join。
4. 在什么时机生成导出文件?目前我是在查询的Action中同时生成了导出文件,否则,到了下一页,我就不知道查询条件了,当然,如果把拼装后的HQL存储在Session或者Hidden中也可以解决这个问题,但是这样就破坏了DAO的封装,要把DAO封装后的HQL发送给Action,然后发送的到Web界面层,所以目前我还在犹豫生成导出文件的时机选择在哪里?
5. 什么时候应该自己获取数据库连接,执行native SQL?具体需要注意些什么?
6. SiteMesh的模板优化?
7. DisplayTag的底层实现?


每个问题都比较棘手,要一个一个解决!

这个框架的优点是:如果熟悉了开发流程,可以大幅度的提高开发速度,如果业务不是很复杂,使用AppGen可以生成60%左右的代码,而且程序可维护性好,因为作者使用了多个设计模式对各个层面进行了封装,所以不同的模块代码风格出奇的一致,有利于开发人员快速上手,也有利于接收其他开发人员遗留的代码。

posted @ 2006-08-17 18:29 刘文涛| 编辑 收藏

Spring对Hibernate有很好的支持。
   
Hibernate中通过SessionFactory创建和维护Session。Spring对SessionFactory的配置进行了整合,无需再通过Hibernate.cfg.xml对SessionFactory进行设定。SessionFactory节点的mappingResources属性包含了映射文件的路径,list节点下可配置多个映射文件。hibernateProperties节点则容纳了所有的属性配置。可以对应传统的Hibernate.cfg.xml文件结构对这里的SessionFactory配置进行解读。

    下面是HibernateSessionFactory 和 HibernateTransactionManager的配置:

    在applicationContext-hibernate.xml中:

 1<bean id="sessionFactory" class="org.springframework.orm.hibernate.LocalSessionFactoryBean">
 2    <property name="dataSource"><ref bean="dataSource"/></property>
 3    <property name="mappingResources">
 4        <list>
 5            <value>com/mycompany/model/User.hbm.xml</value>
 6                ……………………………
 7        </list>
 8    </property>
 9    <property name="hibernateProperties">
10    <props>
11        <prop key="hibernate.dialect">@HIBERNATE-DIALECT@</prop>
12        <!--prop key="hibernate.show_sql">true</prop-->
13        <!--prop key="hibernate.hbm2ddl.auto">update</prop-->
14    </props>
15    </property>
16</bean>

    Spring 提供了一个 HibernateTransactionManager,采用面向Hibernate的TransactionManager实现:org.springframework.orm.hibernate.HibernateTransactionManager。他用线程捆绑了一个Hibernate Session,用它来支持transactions。 

1<bean id="transactionManager" 
2     class="org.springframework.orm.hibernate.HibernateTransactionManager">
3     <property name="sessionFactory"><ref local="sessionFactory"/></property>
4 </bean>

sessionFactory Bean引用了HibernateSessionFactory,而transactionManager Bean引用了HibernateTransactionManage。 transactionManager Bean中有个sessionFactory属性。 HibernateTransactionManager有个sessionFactory setter 和 getter方法,用来在Spring启动的时候实现“依赖注入” (dependency injection)的。 在sessionFactory 属性里引用sessionFactory Bean。这两个对象在Spring容器初始化后就被组装了起来了。
 
    User使用一个TransactionProxyFactoryBean,它定义了一个setTransactionManager()。能很方便的处理申明的事物还有Service Object。TransactionProxyFactoryBean 还有个setter. 这会被Business service object(UserManager)引用, UserManager定义了业务层,并且它还有个属性,由setUserDAO()引用。

    系统持久层中所有的类都继承自Spring提供的HibernateDaoSupport类,HibernateSupport实现了HibernateTemplate和SessionFactory实例的关联。HibernateTemplate对Hibernate Session操作进行了封装,提供了一个简单的方式实现了Hibernate-based DAO对象。借助HibernateTemplate我们可以脱离每次数据操作必须首先获得Session实例、启动事务、提交/回滚事务以及烦杂的try/catch/finally的繁琐操作。一个简单的Hibernate访问方法就完全解决了些麻烦! 无论是在多个DAO接口还是在多方事务的情况下,Spring使得多种DAO对象无缝地协同工作。
    对于简单的单步的动作,象find, load, saveOrUpdate或者delete的调用,HibernateTemplate提供更为便利的选择以代替象一行的回调的执行。此外HibernateDaoSupport类提供了setSessionFactory方法来接受一个SessionFactory,同时提供了getSessionFactory和getHibernateTemplate方法供其继承类使用。将这些结合起来,允许对于典型的需求给出了非常简单的DAO实现,如获得所有用户的方法:
    public List getUsers(User user) {
        return getHibernateTemplate().find("from User u order by upper(u.username)");
    }

posted @ 2006-08-17 17:06 刘文涛| 编辑 收藏

在数据持久层的杰出贡献,可能是Spring最为闪亮的优点。

    Spring提供了通过容器的集约式参数化事务机制,实现事务的外部管理。

容器管理的参数化事务为程序开发提供了相当的灵活性,
同时因为将事务委托给容器进行管理,应用逻辑中无需再编写事务代码,大大节省了代码量
   (特别是针对需要同时操作多个事务资源的应用),从而提高了生产率。

    AppFuse在applicationContext-service.xml文件中进行了对事务的配置

 1 < bean id = " txProxyTemplate "   abstract = " true "
 2          class = " org.springframework.transaction.interceptor.TransactionProxyFactoryBean " >
 3      < property name = " transactionManager " >< ref bean = " transactionManager " /></ property >
 4      < property name = " transactionAttributes " >
 5          < props >
 6              < prop key = " save* " > PROPAGATION_REQUIRED </ prop >
 7              < prop key = " remove* " > PROPAGATION_REQUIRED </ prop >
 8              < prop key = " * " > PROPAGATION_REQUIRED,readOnly </ prop >
 9          </ props >
10      </ property >
11 </ bean >

 这里定义了一个名为txProxyTemplateTransactionProxyFactoryBean服务。它对包含实际数据逻辑的持久层对象进行了事务的封装。在这里,通过transactionAttributes属性,我们指定了事务的管理策略,即将所有的名称以save和remove开头的方法纳入事务管理范围。如果此方法中抛出异常,则Spring将当前事务回滚,如果方法正常结束,则提交事务
   
而对所有其它方法则以只读的事务处理机制进行处理。设为只读型事务,可以使持久层尝试对数据操作进行优化,如对于只读事务Hibernate将不执行flush操作,而某些数据库连接池和JDBC 驱动也对只读型操作进行了特别优化。

如果有其他的方法需要进行写数据库操作,可以在相应的Manager配置中声明。如在UserManager中,就添加了属性

1 < property name = " transactionAttributes " >
2      < props >
3          < prop key = " save* " > PROPAGATION_REQUIRED </ prop >
4          < prop key = " remove* " > PROPAGATION_REQUIRED </ prop >
5          < prop key = " *LoginCookie " > PROPAGATION_REQUIRED </ prop >
6          < prop key = " * " > PROPAGATION_REQUIRED,readOnly </ prop >
7      </ props >
8 </ property >

    这样,以LoginCookie结尾的方法也可以写数据库了。

    Spring可以将任意Java Class 纳入事务管理,而无需对其进行任何修改,

   因此我们的类可能完全不知道它正在被进行事务管理。

posted @ 2006-08-17 17:01 刘文涛| 编辑 收藏

FilterChainProxy(org.acegisecurity.util.FilterChainProxy)是acegi的一个类,具网友讲acegi真的超级难用。但是通过使用acegi我们可以用spring aop直接对service bean的每一个method做权限管理(听起来很过瘾)。

这次我们讲的主要是FilterChainProxy这个类在spring中的应用。

 1 <!--   ========================  FILTER CHAIN  =======================   -->
 2
 3 < bean id = " filterChainProxy "   class = " org.acegisecurity.util.FilterChainProxy " >
 4      < property name = " filterInvocationDefinitionSource " >
 5          < value >
 6             CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON
 7             PATTERN_TYPE_APACHE_ANT
 8              /** =httpSessionContextIntegrationFilter,logoutFilter,authenticationProcessingFilter,
 9                 securityContextHolderAwareRequestFilter,rememberMeProcessingFilter,
10                 anonymousProcessingFilter,exceptionTranslationFilter,filterInvocationInterceptor
11         </value>
12
13             <!-- Put channelProcessingFilter before securityContextHolderAwareRequestFilter to turn on SSL switching -->
14             <!-- It's off by default b/c Canoo WebTest doesn't support SSL out-of-the-box -->
15
16     </property>
17 </bean>

首先在这个类中包含的一个方法

1 setApplicationContext(org.springframework.context.ApplicationContextapplicationContext) 

这个方法首先对web.xml中所定义的applicationContext进行加载. FilterChainProxy的应用要依赖于acegi的另外一个Bean就是 FilterToBeanProxy,需要在web.xml中进行声明:

1 < filter >
2          < filter - name > securityFilter </ filter - name >
3          < filter - class > org.acegisecurity.util.FilterToBeanProxy </ filter - class >
4          < init - param >
5              < param - name > targetClass </ param - name >
6              < param - value > org.acegisecurity.util.FilterChainProxy </ param - value >
7          </ init - param >
8 </ filter >


然后在Filter-mappping中指定所需要过滤的文件

 1 < filter - mapping >
 2      < filter - name > encodingFilter </ filter - name >
 3      < url - pattern >* .jsp </ url - pattern >
 4 </ filter - mapping >

 5 < filter - mapping >
 6      < filter - name > securityFilter </ filter - name >
 7      < url - pattern >/ j_security_check </ url - pattern >
 8 </ filter - mapping >

 9 < filter - mapping >
10      < filter - name > securityFilter </ filter - name >
11      < url - pattern >/ dwr /* </url-pattern>
12 </filter-mapping>

13 <filter-mapping>
14     <filter-name>securityFilter</filter-name>
15     <url-pattern>*.html</url-pattern>
16 </filter-mapping>

17 <filter-mapping>
18     <filter-name>securityFilter</filter-name>
19     <url-pattern>*.jsp</url-pattern>
20 </filter-mapping>  

 

posted @ 2006-08-17 16:21 刘文涛| 编辑