??xml version="1.0" encoding="utf-8" standalone="yes"?>
]]>
数据库设计的范式大纲
W一范式:
对于表中的每一行,必须且仅仅有唯一的行?span lang="EN-US">.在一行中的每一列仅有唯一的值ƈ且具有原子?span lang="EN-US">.
W二范式:
W二范式要求非主键列是主键的子集Q非主键列活动必d全依赖整个主键。主键必L唯一性的元素,一个主键可以由一个或更多的组成唯一值的列组成。一旦创建,主键无法改变Q外键关联一个表的主键。主外键兌意味着一对多的关p?span lang="EN-US">.
W三范式:
W三范式要求非主键列互不依赖.
W四范式:
W四范式止主键列和非主键列一对多关系不受U束
W五范式:
W五范式表分割成尽可能的块,Z排除在表中所有的冗余.
下面先讨论前3个范式:
引言
数据库的设计范式是数据库设计所需要满的规范Q满些规范的数据库是z的、结构明晰的Q同Ӟ不会发生插入
Q?span lang="EN-US">insertQ、删除(deleteQ和更新Q?span lang="EN-US">updateQ操作异常。反之则是ؕ七八p,不仅l数据库的编Eh员制造麻烦,而且面目可憎Q可能存储了 大量不需要的冗余信息?span lang="EN-US">
设计范式是不是很难懂呢?非也Q大学教材上l我们一堆数学公式我们当然看不懂Q也C住。所以我们很多h根本不按照范式来设计数据库?span lang="EN-US">
实质上,设计范式用很形象、很z的话语p说清楚,道明白。本文将对范式进行通俗地说明,q以W者曾l设计的一个简单论坛的数据库ؓ例来讲解怎样这些范式应用于实际工程?span lang="EN-US">
范式说明
W一范式Q?span lang="EN-US">1NFQ:数据库表中的字段都是单一属性的Q不可再分。这个单一属性由基本cd构成Q包括整型、实数、字W型、逻辑型、日期型{?span lang="EN-US">
例如Q如下的数据库表是符合第一范式的:
字段1 |
字段2 |
字段3 |
字段4 |
|
|
|
|
而这L数据库表是不W合W一范式的:
字段1 |
字段2 |
字段3 |
字段4 |
|
|
|
字段3.1 |
字段3.2 |
|
很显Ӟ在当前的M关系数据库管理系l(DBMSQ中Q傻瓜也不可能做ZW合W一范式的数据库Q因?span lang="EN-US">DBMS不允怽把数据库表的一列再分成二列或多列。因此,你想在现有的DBMS中设计出不符合第一范式的数据库都是不可能的?span lang="EN-US">
W二范式Q?span lang="EN-US">2NFQ:数据库表中不存在非关键字D对M候选关键字D늚部分函数依赖Q部分函C赖指的是存在l合关键字中的某些字D决定非关键字段的情况)Q也x有非关键字段都完全依赖于L一l候选关键字?span lang="EN-US">
假定选课关系表ؓSelectCourse(学号, 姓名, q龄, 评名称, 成W, 学分)Q关键字为组合关键字(学号, 评名称)Q因为存在如下决定关p:
(学号, 评名称) ?(姓名, q龄, 成W, 学分)
q个数据库表不满第二范式,因ؓ存在如下军_关系Q?span lang="EN-US">
(评名称) ?(学分)
(学号) ?(姓名, q龄)
卛_在组合关键字中的字段军_非关键字的情c?span lang="EN-US">
׃不符?span lang="EN-US">2NFQ这个选课关系表会存在如下问题Q?span lang="EN-US">
(1) 数据冗余Q?span lang="EN-US">
同一门课E由n个学生选修Q?span lang="EN-US">"学分"重?span lang="EN-US">n-1ơ;同一个学生选修?span lang="EN-US">m门课E,姓名和年龄就重复?span lang="EN-US">m-1ơ?span lang="EN-US">
(2) 更新异常Q?span lang="EN-US">
若调整了某门评的学分,数据表中所有行?span lang="EN-US">"学分"值都要更斎ͼ否则会出现同一门课E学分不同的情况?span lang="EN-US">
(3) 插入异常Q?span lang="EN-US">
假设要开设一门新的课E,暂时q没有h选修。这P׃q没?span lang="EN-US">"学号"关键字,评名称和学分也无法记录入数据库?span lang="EN-US">
(4) 删除异常Q?span lang="EN-US">
假设一批学生已l完成课E的选修Q这些选修记录应该从数据库表中删除。但是,与此同时Q课E名U和学分信息也被删除了。很昄Q这也会D插入异常?span lang="EN-US">
把选课关系?span lang="EN-US">SelectCourse改ؓ如下三个表:
学生Q?span lang="EN-US">Student(学号, 姓名, q龄)Q?span lang="EN-US">
评Q?span lang="EN-US">Course(评名称, 学分)Q?span lang="EN-US">
选课关系Q?span lang="EN-US">SelectCourse(学号, 评名称, 成W)?span lang="EN-US">
q样的数据库表是W合W二范式的,消除了数据冗余、更新异常、插入异常和删除异常?span lang="EN-US">
另外Q所有单关键字的数据库表都符合第二范式,因ؓ不可能存在组合关键字?span lang="EN-US">
W三范式Q?span lang="EN-US">3NFQ:在第二范式的基础上,数据表中如果不存在非关键字段对Q一候选关键字D늚传递函C赖则W合W三范式。所谓传递函C赖,指的是如
果存?span lang="EN-US">"A ?B ?C"的决定关p,?span lang="EN-US">C传递函C赖于A。因此,满W三范式的数据库表应该不存在如下依赖关系Q?span lang="EN-US">
关键字段 ?非关键字D?span lang="EN-US">x ?非关键字D?span lang="EN-US">y
假定学生关系表ؓStudent(学号, 姓名, q龄, 所在学?span lang="EN-US">, 学院地点, 学院电话)Q关键字为单一关键?span lang="EN-US">"学号"Q因为存在如下决定关p:
(学号) ?(姓名, q龄, 所在学?span lang="EN-US">, 学院地点, 学院电话)
q个数据库是W合2NF的,但是不符?span lang="EN-US">3NFQ因为存在如下决定关p:
(学号) ?(所在学?span lang="EN-US">) ?(学院地点, 学院电话)
卛_在非关键字段"学院地点"?span lang="EN-US">"学院电话"对关键字D?span lang="EN-US">"学号"的传递函C赖?span lang="EN-US">
它也会存在数据冗余、更新异常、插入异常和删除异常的情况,读者可自行分析得知?span lang="EN-US">
把学生关p表分ؓ如下两个表:
学生Q?span lang="EN-US">(学号, 姓名, q龄, 所在学?span lang="EN-US">)Q?span lang="EN-US">
学院Q?span lang="EN-US">(学院, 地点, 电话)?span lang="EN-US">
q样的数据库表是W合W三范式的,消除了数据冗余、更新异常、插入异常和删除异常?span lang="EN-US">
鲍依?span lang="EN-US">-U得范式Q?span lang="EN-US">BCNFQ:在第三范式的基础上,数据库表中如果不存在M字段对Q一候选关键字D늚传递函C赖则W合W三范式?span lang="EN-US">
假设仓库理关系表ؓStorehouseManage(仓库ID,
存储物品ID, 理?span lang="EN-US">ID, 数量)Q且有一个管理员只在一个仓库工作;一个仓库可以存储多U物品。这个数据库表中存在如下军_关系Q?span lang="EN-US">
(仓库ID, 存储物品ID) ?理?span lang="EN-US">ID, 数量)
(理?span lang="EN-US">ID, 存储物品ID) ?(仓库ID, 数量)
所以,(仓库ID, 存储物品ID)?span lang="EN-US">(理?span lang="EN-US">ID, 存储物品ID)都是StorehouseManage的候选关键字Q表中的唯一非关键字Dؓ数量Q它是符合第三范式的。但是,׃存在如下军_关系Q?span lang="EN-US">
(仓库ID) ?(理?span lang="EN-US">ID)
(理?span lang="EN-US">ID) ?(仓库ID)
卛_在关键字D决定关键字D늚情况Q所以其不符?span lang="EN-US">BCNF范式。它会出现如下异常情况:
(1) 删除异常Q?span lang="EN-US">
当仓库被清空后,所?span lang="EN-US">"存储物品ID"?span lang="EN-US">"数量"信息被删除的同时Q?span lang="EN-US">"仓库ID"?span lang="EN-US">"理?span lang="EN-US">ID"信息也被删除了?span lang="EN-US">
(2) 插入异常Q?span lang="EN-US">
当仓库没有存储Q何物品时Q无法给仓库分配理员?span lang="EN-US">
(3) 更新异常Q?span lang="EN-US">
如果仓库换了理员,则表中所有行的管理员ID都要修改?span lang="EN-US">
把仓库管理关p表分解Z个关p表Q?span lang="EN-US">
仓库理Q?span lang="EN-US">StorehouseManage(仓库ID, 理?span lang="EN-US">ID)Q?span lang="EN-US">
仓库Q?span lang="EN-US">Storehouse(仓库ID, 存储物品ID, 数量)?span lang="EN-US">
q样的数据库表是W合BCNF范式的,消除了删除异常、插入异常和更新异常?b>
范式应用
我们来逐步搞定一个论坛的数据库,有如下信息:
Q?span lang="EN-US">1Q?用户Q用户名Q?span lang="EN-US">emailQ主,电话Q联pd址
Q?span lang="EN-US">2Q?帖子Q发帖标题,发帖内容Q回复标题,回复内容
W一ơ我们将数据库设计ؓ仅仅存在表:
用户?span lang="EN-US"> |
email |
主页 |
电话 |
联系地址 |
发帖标题 |
发帖内容 |
回复标题 |
回复内容 |
q个数据库表W合W一范式Q但是没有Q何一l候选关键字能决定数据库表的整行Q唯一的关键字D는户名也不能完全决定整个元l。我们需要增?span lang="EN-US">"发帖ID"?span lang="EN-US">"回复ID"字段Q即表修改为:
用户?span lang="EN-US"> |
email |
主页 |
电话 |
联系地址 |
发帖ID |
发帖标题 |
发帖内容 |
回复ID |
回复标题 |
回复内容 |
q样数据表中的关键字(用户名,发帖IDQ回?span lang="EN-US">ID)能决定整行:
(用户?span lang="EN-US">,发帖ID,回复ID) ?(email,主页,电话,联系地址,发帖标题,发帖内容,回复标题,回复内容)
但是Q这L设计不符合第二范式,因ؓ存在如下军_关系Q?span lang="EN-US">
(用户?span lang="EN-US">) ?(email,主页,电话,联系地址)
(发帖ID) ?(发帖标题,发帖内容)
(回复ID) ?(回复标题,回复内容)
即非关键字段部分函数依赖于候选关键字D,很明显,q个设计会导致大量的数据冗余和操作异常?span lang="EN-US">
我们数据库表分解ؓQ带下划U的为关键字Q:
Q?span lang="EN-US">1Q?用户信息Q用户名Q?span lang="EN-US">emailQ主,电话Q联pd址
Q?span lang="EN-US">2Q?帖子信息Q发?span lang="EN-US">IDQ标题,内容
Q?span lang="EN-US">3Q?回复信息Q回?span lang="EN-US">IDQ标题,内容
Q?span lang="EN-US">4Q?发脓Q用户名Q发?span lang="EN-US">ID
Q?span lang="EN-US">5Q?回复Q发?span lang="EN-US">IDQ回?span lang="EN-US">ID
q样的设计是满W?span lang="EN-US">1?span lang="EN-US">2?span lang="EN-US">3范式?span lang="EN-US">BCNF范式要求的,但是q样的设计是不是最好的呢?
不一定?span lang="EN-US">
观察可知Q第4?span lang="EN-US">"发帖"中的"用户?span lang="EN-US">"?span lang="EN-US">"发帖ID"之间?span lang="EN-US">1Q?span lang="EN-US">N的关p,因此我们可以?span lang="EN-US">"发帖"合ƈ到第2的"帖子信息"中;W?span lang="EN-US">5?span lang="EN-US">"回复"中的 "发帖ID"?span lang="EN-US">"回复ID"之间也是1Q?span lang="EN-US">N的关p,因此我们可以?span lang="EN-US">"回复"合ƈ到第3的"回复信息"中。这样可以一定量地减数据冗余,新的设计为:
Q?span lang="EN-US">1Q?用户信息Q用户名Q?span lang="EN-US">emailQ主,电话Q联pd址
Q?span lang="EN-US">2Q?帖子信息Q用户名Q发?span lang="EN-US">IDQ标题,内容
Q?span lang="EN-US">3Q?回复信息Q发?span lang="EN-US">IDQ回?span lang="EN-US">IDQ标题,内容
数据库表1昄满所有范式的要求Q?span lang="EN-US">
数据库表2中存在非关键字段"标题"?span lang="EN-US">"内容"对关键字D?span lang="EN-US">"发帖ID"的部分函C赖,即不满W二范式的要求,但是q一设计q不会导致数据冗余和操作异常Q?span lang="EN-US">
数据库表3中也存在非关键字D?span lang="EN-US">"标题"?span lang="EN-US">"内容"对关键字D?span lang="EN-US">"回复ID"的部分函C赖,也不满W二范式的要求,但是与数据库?span lang="EN-US">2怼Q这一设计也不会导致数据冗余和操作异常?span lang="EN-US">
由此可以看出Qƈ不一定要满范式的要求,对于1Q?span lang="EN-US">N关系Q当1的一边合q到N的那边后Q?span lang="EN-US">N的那边就不再满W二范式了,但是q种设计反而比较好Q?span lang="EN-US">
对于MQ?span lang="EN-US">N的关p,不能?span lang="EN-US">M一ҎN一边合q到另一边去Q这样会D不符合范式要求,同时D操作异常和数据冗余?span lang="EN-US">
对于1Q?span lang="EN-US">1的关p,我们可以左边的1或者右边的1合ƈ到另一边去Q设计导致不W合范式要求Q但是ƈ不会D操作异常和数据冗余?span lang="EN-US">
l论
满范式要求的数据库设计是结构清晰的Q同时可避免数据冗余和操作异常。这q意味着不符合范式要求的设计一定是错误的,在数据库表中存在1Q?span lang="EN-US">1?span lang="EN-US">1Q?span lang="EN-US">N关系q种较特D的情况下,合ƈD的不W合范式要求反而是合理的?span lang="EN-US">
在我们设计数据库的时候,一定要时刻考虑范式的要求?/span>
Spring 中进行事务管理的通常方式是利用AOPQ面向切片编E)的方式,为普通javacd装事务控Ӟ它是通过动态代理实现的Q由于接口是延迟实例化的Q? spring在这D|间内通过拦截器,加蝲事务切片。原理就是这P具体l节请参考jdk中有兛_态代理的文档。本文主要讲解如何在spring中进行事 务控制?br>动态代理的一个重要特征是Q它是针Ҏ口的Q所以我们的dao要通过动态代理来让spring接管事务Q就必须在dao前面抽象Z个接口,当然如果没有q样的接口,那么spring会用CGLIB来解决问题,但这不是spring推荐的方式,所以不做讨?
大多数Spring用户选择声明式事务管理。这是最媄响应用代码的选择Q?因而这是和非R入?/em>的轻量容器的观忉|一致的?
从考虑EJB CMT和Spring声明式事务管理的怼以及不同之处出发是很有益的?它们的基本方法是怼的:都可以指定事务管理到单独的方法;如果需要可以在事务?下文调用 不象EJB CMTl定在JTA上,Spring声明式事务管理可以在M环境下用?只需更改配置文gQ它可以和JDBC、JDO、Hibernate或其他的事务机制一起工? Spring可以使声明式事务理应用到普通Java对象Q不仅仅是特D的c,如EJB Spring提供声明?span class="emphasis">回滚规则QEJB没有对应的特性, 我们在下面讨论q个Ҏ。回滚可以声明式控制Q不仅仅是编E式? Spring允许你通过AOP定制事务行ؓ。例如,如果需要,你可以在事务 回滚中插入定制的行ؓ。你也可以增加Q意的通知Q就象事务通知一栗?EJB CMTQ除了?tt class="literal">pȝ异常Q通常是运行时异常Q, EJB容器自动回滚事务。EJB CMT遇到应用E序异常 Q除?span class="emphasis">java.rmi.RemoteException外的checked异常Q时?会自动回滚事务。虽然Spring声明式事务管理沿用EJB的约定(遇到unchecked 异常自动回滚事务Q,但是q是可以定制的?/p> 按照我们的测试,Spring声明式事务管理的性能要胜qEJB CMT?/p> ?
帔R过TransactionProxyFactoryBean讄Spring事务代理。我们需
要一个目标对象包装在事务代理中。这个目标对象一般是一个普通Java对象的bean。当?
们定义TransactionProxyFactoryBeanӞ必须提供一个相关的 PlatformTransactionManager的引用和事务属?/b>?事务属?/b>含有上面描述的事务定义?/p> ?
务代理会实现目标对象的接口:q里是id为petStoreTarget的bean。(使用
CGLIB也可以实现具体类的代理。只要设|proxyTargetClass属性ؓtrue可以?
如果目标对象没有实现M接口Q这自动设|该属性ؓtrue。通常Q我们希望面向接口而不?
cȝE。)使用proxyInterfaces属性来限定事务代理来代 理指定接口也是可以的Q一般来说是个好xQ。也可以通过?-前缀强制回滚Q?前缀指定提交Q这允许即抛出unchecked异常时也可以提交事务Q当然你自己要明白自?在做什么)?/p> PROPAGATION_REQUIRES_NEW, -MyException <bean id="petStore"
class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
<property name="transactionManager"><ref bean="transactionManager"/></property>
<property name="target"><ref bean="petStoreTarget"/></property>
<property name="transactionAttributes">
<props>
<prop key="insert*">PROPAGATION_REQUIRED,-MyCheckedException</prop>
<prop key="update*">PROPAGATION_REQUIRED</prop>
<prop key="*">PROPAGATION_REQUIRED,readOnly</prop>
</props>
</property>
</bean>
</prop>
注:上面的意思是addҎ独占一个事务,当事务处理过E中产生MyException异常或者该异常的子cd回滚该事务?br>
<prop key="loadAll">
PROPAGATION_SUPPORTS, ISOLATION_READ_COMMITED, Readonly
</prop>
注:表示loadAllҎ支持事务Q而且不会d没有提交事务的数据。它的数据ؓ只读Q这h助于提高d的性能Q?br>
附A Spring中的所有事务策?br>
PROPAGATION_MANDATORY
PROPAGATION_NESTED
PROPAGATION_NEVER
PROPAGATION_NOT_SUPPORTED
PROPAGATION_REQUIRED
PROPAGATION_REQUIRED_NEW
PROPAGATION_SUPPORTS
附B Spring中所有的隔离{略Q?br>
ISOLATION_DEFAULT
ISOLATION_READ_UNCOMMITED
ISOLATION_COMMITED
ISOLATION_REPEATABLE_READ
ISOLATION_SERIALIZABLE
]]>
Read Ted's email here, but the gist of it is this: WebWork is a great technology, and Struts is a great community. It's a perfect match and bringing the two together will only be better for WebWork and Struts users alike. The only down side for me is that I'll be working less with OpenSymphony, but I believe that is a small price for all the great benefits that come from this merger.
Just to be clear, WebWork is not going away. WebWork 2.2 is still coming out any day now, and there may even be a WebWork 2.3. But new minor/major versions won't be coming out under the WebWork name for much longer. Instead, they will be released under the Struts incubator program with the intent to eventually become Struts Action Framework 2.0.
So don't worry, WebWork 2.1.8, 2.2.1, and other bug fix releases will continue to come out and we will support the WebWork community as long as needed. In addition, we'll make compatibility with both Struts and WebWork a high priority, so future releases may help with that. To be clear: no one is leaving WebWork and it will continue to be supported for a very long time.
With this renewed energy, larger development team, and larger
community, the combined efforts of Struts and WebWork will surely make
the Struts platform the easiest, fastest, and most powerful Java web
framework available. We hope that all the WebWork users and developers
are as excited about this as we are and are ready to take WebWork to
the next level.
原文地址Qhttp://www.opensymphony.com/webwork/
以前一直在struts和webwork之间犹UQ看来struts气数未尽呀。apachel织q是比较只值得信赖的。呵?
您肯定已l听说过控制反{ (IOC) 设计模式Q因为很长一D|间以来一直在传关于它的信息。如果您在Q何功能中使用q?Spring 框架Q那么您q道其原理的作用。在本文中,我利用这一原理把一?Struts 应用E序注入 Spring 框架Q您亲w体会到 IOC 模式的强大?/font>
一?Struts 应用E序整合q?Spring 框架h多方面的优点。首先,Spring 是ؓ解决一些关? JEE 的真实世界问题而设计的Q比如复杂性、低性能和可试性,{等。第二,Spring 框架包含一?AOP 实现Q允许您面向方面技术应用于面向对象的代码。第三,一些h可能会说 Spring 框架只有处理 Struts ?Struts 处理自己好。但是这是观炚w题,我演CZU将 Struts 应用E序整合?Spring 框架的方法后Q具体由您自己决定用哪一U?/font>
我所演示的方法都是执行v来相对简单的Q但是它们却h明显不同的优炏V我为每一U方法创Z一个独立而可用的例子Q这h可以完全理解每U方法? 请参?下蝲 部分获得完整例子源代码。请参阅 参考资?/a>Q下?Struts MVC ?Spring 框架?/font>
Spring 的创立?Rod Johnson 以一U批判的眼光看待 Java?企业软g开发,q且提议很多企业N都能够通过战略C?IOC 模式Q也UC依赖注入Q来解决。当 Rod 和一个具有奉献精的开放源码开发者团队将q个理论应用于实跉|Q结果就产生?Spring 框架。简a之,Spring 是一个轻型的容器Q利用它可以使用一个外?XML 配置文g方便地将对象q接在一赗每个对象都可以通过昄一? JavaBean 属性收C个到依赖对象的引用,留给您的单Q务就只是在一?XML 配置文g中把它们q接好?/font>
![]() |
|
? 赖注入是一个强大的Ҏ,但是 Spring 框架能够提供更多Ҏ。Spring 支持可插拔的事务理器,可以l您的事务处理提供更q泛的选择范围。它集成了领先的持久性框Ӟq且提供一个一致的异常层次l构。Spring q提供了一U用面向方面代码代替正常的面向对象代码的简单机制?/font>
Spring AOP 允许您?i>拦截?/i> 在一个或多个执行点上拦截应用E序逻辑。加强应用程序在拦截器中的日志记录逻辑会生一个更可读的、实用的代码基础Q所以拦截器q泛用于日志记录。您很快׃看到Qؓ了处理横切关注点QSpring AOP 发布了它自己的拦截器Q您也可以编写您自己的拦截器?/font>
![]() |
? Struts 怼QSpring 可以作ؓ一?MVC 实现。这两种框架都具有自q优点和缺点,管大部分h同意 Struts ?MVC 斚w仍然是最好的。很多开发团队已l学会在旉紧迫的时候利?Struts 作ؓ构造高品质软g的基。Struts h如此大的推动力,以至于开发团队宁愿整?Spring 框架的特性,而不愿意转换?Spring MVC。没必要q行转换Ҏ来说是一个好消息。Spring 架构允许您将 Struts 作ؓ Web 框架q接到基?Spring 的业务和持久层。最后的l果是现在一切条仉具备了?/font>
在接下来的小H门中,您将会了解到三种?Struts MVC 整合?Spring 框架的方法。我揭C每U方法的~陷q且Ҏ它们的优炏V?一旦您了解到所有三U方法的作用Q我会向您展示一个o人兴奋的应用E序Q这个程序用的是这三种Ҏ中我最喜欢的一U?/font>
![]() |
接下来的每种整合技术(或者窍门)都有自己的优点和特点。我偏爱其中的一U,但是我知道这三种都能够加深您?Struts ?Spring 的理解。在处理各种不同情况的时候,q将l您提供一个广阔的选择范围。方法如下:
ActionSupport
cL?StructsDelegatingRequestProcessor
覆盖 Struts ? RequestProcessor
Action
理委托l?Spring 框架无论您用哪U技术,都需要?Spring ?ContextLoaderPlugin
?Struts ?ActionServlet
装蝲 Spring 应用E序环境。就像添加Q何其他插件一P单地向您?struts-config.xml 文gd该插Ӟ如下所C:
|
前面已经提到q,?下蝲 部分Q您能够扑ֈq三个完全可使用的例子的完整源代码。每个例子都Z个书c搜索应用程序提供一U不同的 Struts ?Spring 的整合方法。您可以在这里看C子的要点Q但是您也可以下载应用程序以查看所有的l节?/font>
![]() |
H门 1. 使用 Spring ?ActionSupport
手动创徏一?Spring 环境是一U整?Struts ?Spring 的最直观的方式。ؓ了它变得更单,Spring 提供了一些帮助。ؓ了方便地获得 Spring 环境Q?font size="3">org.springframework.web.struts.ActionSupport
cL供了一?getWebApplicationContext()
Ҏ。您所做的只是?Spring ?ActionSupport
而不?font size="3"> Struts Action
|
让我们快速思考一下这里到底发生了什么。在 (1) 处,我通过?Spring ?ActionSupport
c而不?Struts ?Action
c进行扩展,创徏了一个新?Action
?/font>?(2) 处,我?getWebApplicationContext()
Ҏ获得一?ApplicationContext
?/font>Z获得业务服务Q我使用?(2) 处获得的环境?(3) 处查找一?Spring bean?/font>
q? U技术很单ƈ且易于理解。不q的是,它将 Struts 动作?Spring 框架耦合在一赗如果您x换掉 SpringQ那么您必须重写代码。ƈ且,׃ Struts 动作不在 Spring 的控制之下,所以它不能获得 Spring AOP 的优ѝ当使用多重独立?Spring 环境Ӟq种技术可能有用,但是在大多数情况下,q种Ҏ不如另外两种Ҏ合适?/font>
![]() |
?Spring ?Struts 动作中分L一个更巧妙的设计选择。分ȝ一U方法是使用 org.springframework.web.struts.DelegatingRequestProcessor
cL覆盖 Struts ?font size="3"> RequestProcessor
处理E序Q如清单 2 所C:
|
我利用了 <controller>
标记来用 DelegatingRequestProcessor
覆盖默认?Struts RequestProcessor
?/font>下一步是在我?Spring 配置文g中注册该动作Q如清单 3 所C:
|
注意Q在 (1) 处,我用名U属性注册了一?beanQ以匚w struts-config 动作映射名称?code>SearchSubmit 动作揭示了一?JavaBean 属性,允许 Spring 在运行时填充属性,如清?4 所C:
|
在清?4 中,您可以了解到如何创徏 Struts 动作。在 (1) 处,我创Z一?JavaBean 属性?code>DelegatingRequestProcessor? 动地配置q种属性。这U设计 Struts 动作q不知道它正?Spring 理Qƈ且您能够利?Sping 的动作管理框架的所有优炏V由于您?Struts 动作注意不到 Spring 的存在,所以您不需要重写您?Struts 代码可以用其他控制反转容器来替换?Spring?/font>
DelegatingRequestProcessor
Ҏ的确比第一U方法好Q但是仍然存在一些问题。如果您使用一个不同的 RequestProcessor
Q?/font>则需要手动整?Spring ?DelegatingRequestProcessor
?/font>d的代码会造成l护的麻烦ƈ且将来会降低您的应用E序的灵zL。此外,q有q一些用一pd命o来代?Struts RequestProcessor
的传闅R?q种改变会对这U解x法的使用寿命造成负面的媄响?/font>
![]() |
一个更好的解决Ҏ是将 Strut 动作理委托l?Spring。您可以通过?struts-config
动作映射中注册一个代理来实现。代理负责在 Spring 环境中查?Struts 动作。由于动作在 Spring 的控制之下,所以它可以填充动作?JavaBean 属性,qؓ应用诸如 Spring ?AOP 拦截器之cȝҎ带来了可能?
清单 5 中的 Action
cM清单 4 中的相同。但?struts-config 有一些不同:
|
清单 5 是一个典型的
struts-config.xml 文gQ只有一个小的差别。它注册 Spring
代理cȝ名称Q而不是声明动作的cdQ如Q?Q处所C。DelegatingActionProxy cM用动作映名U查?Spring
环境中的动作。这是我们使用 ContextLoaderPlugIn
声明的环境?/font>
一?Struts 动作注册Z?Spring bean 是非常直观的Q如清单 6 所C。我利用动作映射使用 <bean>
标记的名U属性(在这个例子中?"/searchSubmit
"Q简单地创徏了一?bean。这个动作的 JavaBean 属性像M Spring bean 一栯填充Q?
|
![]() |
动作委托解决Ҏ是这三种Ҏ中最好的。Struts 动作不了?SpringQ不对代码作M改变可用于?Spring 应用E序中?font size="3">RequestProcessor
的改变不会媄响它Qƈ且它可以利用 Spring AOP Ҏ的优点?
动作委托的优点不止如此。一旦让 Spring 控制您的 Struts 动作Q您可以?Spring l动作补充更强的zd。例如,没有 Spring 的话Q所有的 Struts 动作都必LU程安全的。如果您讄 <bean>
标记?singleton
属性ؓ“false”,那么不管用何U方法,您的应用E序都将在每一个请求上有一个新生成的动作对象。您可能不需要这U特性,但是把它攑֜您的工具׃?
很好。您也可以利?Spring 的生命周期方法。例如,当实例化 Struts 动作Ӟ<bean>
标记?init-method 属性被用于q行一个方法。类似地Q在从容器中删除 bean 之前Qdestroy-method 属性执行一个方法。这些方法是理昂贵对象的好办法Q它们以一U与 Servlet 生命周期相同的方式进行管理?/font>
![]() |
? 面提到过Q通过?Struts 动作委托l?Spring 框架而整?Struts ?Spring 的一个主要的优点是:您可以将 Spring ?AOP 拦截器应用于您的 Struts 动作。通过?Spring 拦截器应用于 Struts 动作Q您可以用最的代h处理横切x炏V?/font>
虽然 Spring 提供很多内置拦截器,但是我将向您展示如何创徏自己的拦截器q把它应用于一?Struts 动作。ؓ了用拦截器Q您需要做三g事:
q看h非常单的几句话却非常强大。例如,在清?7 中,我ؓ Struts 动作创徏了一个日志记录拦截器? q个拦截器在每个Ҏ调用之前打印一句话Q?/font>
|
q个拦截器非常简单?code>before() Ҏ在拦截点中每个方法之前运行。在本例中,它打印出一句话Q其实它可以做您惛_的Q何事。下一步就是在 Spring 配置文g中注册这个拦截器Q如清单 8 所C:
|
您可能已l注意到了,清单 8 扩展?清单 6 中所C的应用E序以包含一个拦截器。具体细节如下:
<value>
标记?/font>是q样。就像这个例子所展示的,您?Struts 动作|于 Spring 框架的控制之下,为处理您?Struts 应用E序提供了一pd全新的选择。在本例中,使用动作委托可以L地利?Spring 拦截器提?Struts 应用E序中的日志记录能力?/font>
![]() |
在本文中Q您已经学习了将 Struts 动作整合?Spring 框架中的三种H门。?Spring ?ActionSupport
来整?StrutsQ第一U窍门中是q样做的Q简单而快P但是会将 Struts 动作?Spring 框架耦合在一赗如果您需要将应用E序ULC个不同的框架Q则需要重写代码。第二种解决Ҏ通过委托 RequestProcessor
巧妙地解开代码的耦合Q但是它的可扩展性不强,q且?Struts ?RequestProcessor
变成一pd命oӞq种Ҏ持l不了很长时间。第三种Ҏ是这三种Ҏ中最好的Q将 Struts 动作委托l?Spring 框架可以使代码解耦,从而您可以在您的 Struts 应用E序中利?Spring 的特性(比如日志记录拦截器)?/p>
三种 Struts-Spring 整合H门中的每一U都被实现成一个完整可用的应用E序。请参阅 下蝲 部分仔细研究它们?/font>
![]() |
描述 | 名字 | 大小 | 下蝲Ҏ |
---|---|---|---|
ActionSupport sample code | j-sr2-actionsupport.zip | 5 MB | FTP |
RequestProcessor sample code | j-sr2-requestprocessor.zip | 5 MB | FTP |
Delegate sample code | j-sr2-delegate.zip | 5 MB | FTP |