??xml version="1.0" encoding="utf-8" standalone="yes"?>
Q?Q修改WEB-INF目录的web.xml
定义DispatcherServlet来控制所有的hQ同时具有一个标准的servlet-mapping映射?.htm URL模式
创徏springapp-servlet.xmlQ应用程序名--servlet.xmlQ,配置DispatcherServlet要用的Web应用E序context
定义名ؓspringappController的Bean条目Q指向SpringappController控制?/p>
使用SimpleUrlHandlerMapping来定义URL映射Q将/hello.htm映射到SpringappController控制?/p>
Q?Q拷贝jars到WEB-INF/lib目录
dist/spring.jar、lib/jakarta-commons/commons-logging.jar、lib/log4j/log4j-1.2.8.jar文g导入到springapp工程的springapp/WEB-INF/lib目录?/p>
Q?Q创建控制器
实现Controller接口的handleRequest()Ҏ来处理请?/p>
q里d日志记录Q检查是否执行到q里
handleRequest()Ҏq回的ModelAndView没有指定ModelQ所以直接重定向到指定的视图hello.jsp
Q?0Q创图hello.jsp
1 Q核心容?/font>Q核心容器提?Spring 框架的基本功能。核心容器的主要lg?BeanFactoryQ它是工厂模式的实现。BeanFactory 使用控制反{ QIOCQ?模式应用程序的配置和依赖性规范与实际的应用程序代码分开? Spring 框架的功能可以用在Q?J2EE 服务器中Q大多数功能也适用于不受管理的环境。Spring 的核心要ҎQ支持不l定到特?J2EE 服务的可重用业务和数据访问对象。毫无疑问,q样的对象可以在不同 J2EE 环境 QWeb ?EJBQ、独立应用程序、测试环境之间重用?
控制反{模式Q也UC依赖性介入)的基本概忉|Q不创徏对象Q但是描q创建它们的方式。在代码中不直接与对象和服务q接Q但在配|文件中描述哪一个组仉要哪一Ҏ务。容?Q在 Spring 框架中是 IOC 容器Q?负责这些联pd一赗?/p>
在典型的 IOC 场景中,容器创徏了所有对象,q设|必要的属性将它们q接在一P军_什么时间调用方法。下表列Z IOC 的一个实现模式?/p>
cd 1 服务需要实C门的接口Q通过接口Q由对象提供q些服务Q可以从对象查询依赖性(例如Q需要的附加服务Q?
Spring 框架?IOC 容器采用cd 2 和类? 实现?/strong>
面向斚w的编E?/font>
面向斚w的编E,?AOPQ是一U编E技术,它允许程序员?font color="#0000ff">横切x?/font>?font color="#0000ff">横切典型的职责分界线的行?/font>Q例如日志和事务理Q进行模块化?u>AOP 的核心构造是斚wQ它那些媄响多个类的行为封装到可重用的模块中?/u> AOP ?IOC 是补充性的技术,它们都运用模块化方式解决企业应用E序开发中的复杂问题。在典型的面向对象开发方式中Q可能要日志记录语句放在所有方法和 Java cM才能实现日志功能。在 AOP 方式中,可以反过来将日志服务模块化,q以声明的方式将它们应用到需要日志的lg上。当Ӟ优势是 Java cM需要知道日志服务的存在Q也不需要考虑相关的代码。所以,?Spring AOP ~写的应用程序代码是松散耦合的?/p>
AOP 的功能完全集成到?Spring 事务理、日志和其他各种Ҏ的上下文中?/p>
IOC 容器
Spring 设计的核心是 org.springframework.beans 包,它的设计目标是与 JavaBean lg一起用。这个包通常不是qL接用,而是由服务器其用作其他多数功能的底层中介。下一个最高抽象?BeanFactory 接口Q它是工厂设计模式的实现Q允讔R过名称创徏和检索对象。BeanFactory 也可以管理对象之间的关系?/p>
BeanFactory 支持两个对象模型?/p>
单?/font> 模型提供了具有特定名U的对象的共享实例,可以在查询时对其q行索。Singleton 是默认的也是最常用的对象模型。对于无状态服务对象很理想?br /> BeanFactory 接口 因ؓ org.springframework.beans.factory.BeanFactory 是一个简单接口,所以可以针对各U底层存储方法实现。最常用?BeanFactory 定义?XmlBeanFactoryQ它Ҏ XML 文g中的定义装入 beanQ如清单 1 所C?/p>
?XML 文g中定义的 Bean 是被消极加蝲的,q意呛_需?bean 之前Qbean 本n不会被初始化。要?BeanFactory ?beanQ只需调用 getBean() ҎQ传入将要检索的 bean 的名U即可,如清?2 所C?/p>
每个 bean 的定义都可以?POJO Q用cd?JavaBean 初始化属性定义) ?FactoryBean。FactoryBean 接口Z?Spring 框架构徏的应用程序添加了一个间接的U别?/p>
IOC CZ
理解控制反{最单的方式是看它的实际应用。在对由三部分组成的 Spring pd 的第 1 部分q行ȝӞ我用了一个示例,演示了如何通过 Spring IOC 容器注入应用E序的依赖关p(而不是将它们构徏q来Q?/p>
我用开启在U信用帐L用例作ؓL。对于该实现Q开启信用帐戯求用户与以下服务q行交互Q?
信用U别评定服务Q查询用L信用历史信息?
对于q个CZQ我假设服务已经存在Q理想的情况是用松散耦合的方式把它们集成在一赗以下清单显CZ三个服务的应用程序接口?/p>
清单 3 所C的信用U别评定接口提供了信用历史信息。它需要一个包含客户信息的 Customer 对象。该接口的实现是?CreditRating cL供的?/p>
EmailInterface 负责向客户发送关于客户信用卡状态的电子邮g。邮仉|参敎ͼ例如 SMPT L、用户名、口令)由前面提到的 bean 配置机制讄。Email cL供了该接口的实现?/p>
q些接口׃之后Q接下来要考虑的就是如?font color="#0000ff">用松散耦合方式 注意Q所有的 setter Ҏ都是?Spring 的配|?bean 实现的。所有的依赖关系 Q也是三个接口Q都可以?Spring 框架用这?bean 注入。createCreditCardAccount() Ҏ会用服务L行其余实现?br />
2 QSpring 上下?/font>QSpring 上下文是一个配|文Ӟ?Spring 框架提供上下文信息。Spring 上下文包括企业服务,例如 JNDI、EJB、电子邮件、国际化、校验和调度功能?
3 QSpring AOPQ通过配置理Ҏ,Spring AOP 模块直接?u>面向斚w的编E?/u>功能集成CSpring 框架中。所以可以很ҎC Spring 框架理的Q何对象支持AOP。Spring AOP 模块为基于Spring 的应用程序中的对象提供了事务理服务。通过使用 Spring AOPQ不用依?EJB lgQ就可以声明性事务管理集成到应用E序中?
4QSpring DAOQJDBC DAO 抽象层提供了有意义的异常层次l构Q可用该l构来管理异常处理和不同数据库供应商抛出的错误消息。异常层ơ结构简化了错误处理Qƈ且极大地降低了需要编写的异常代码数量Q例如打开和关闭连接)。Spring DAO 的面?JDBC 的异帔R从通用?DAO 异常层次l构?br />
5 QSpring ORMQSpring 框架插入了若q个 ORM 框架Q从而提供了 ORM 的对象关pdP其中包括 JDO、Hibernate ?iBatis SQL Map。所有这些都遵从 Spring 的通用事务?DAO 异常层次l构?br />
6 QSpring Web 模块QWeb 上下文模块徏立在应用E序上下文模块之上,为基?Web 的应用程序提供了上下文。所以,Spring 框架支持?Jakarta Struts 的集成。Web 模块q简化了处理多部分请求以及将h参数l定到域对象的工作?
7 QSpring MVC 框架QMVC 框架是一个全功能的构?Web 应用E序?MVC 实现。通过{略接口QMVC 框架变成为高度可配置的,MVC 容纳了大量视图技术,其中包括 JSP、Velocity、Tiles、iTextQPDFQ??POIQExcelQ?/p>
IOC ?AOP
cd 2 通过 JavaBean 的属性(例如 setter ҎQ分配依赖?
cd 3 依赖性以构造函数的形式提供Q不?JavaBean 属性的形式公开
原型 模型保每次索都会创建单独的对象。在每个用户都需要自q对象Ӟ原型模型最适合?br />
bean 工厂的概忉| Spring 作ؓ IOC 容器的基。IOC 处理事情的责Q从应用程序代码{Ud框架。正如我在下一个示例中演示的那PSpring 框架使用 JavaBean 属性和配置数据来指出必设|的依赖关系?/p>
BeanFactory factory
=
new
XMLBeanFactory(
new
FileInputSteam(
"
mybean.xml
"
));
MyBean mybean
=
(MyBean) factory.getBean(
"
mybean
"
);
q程信息链接服务Q插入客户信息,客户信息与信用卡和银行信息q接hQ以q行自动借记Q如果需要的话)?
电子邮g服务Q向用户发送有关信用卡状态的电子邮g?/p>
三个接口
public
interface
CreditRatingInterface
{
public
boolean
getUserCreditHistoryInformation(ICustomer iCustomer);
}
public
interface
CreditLinkingInterface
{
public
String getUrl();
public
void
setUrl(String url);
public
void
linkCreditBankAccount()
throws
Exception ;
}
信用链接接口信用历史信息与银行信息Q如果需要的话)q接在一Pq插入用L信用卡信息。信用链接接口是一个远E服务,它的查询是通过 getUrl() Ҏq行的。URL ?Spring 框架?bean 配置机制讄Q我E后会讨论它。该接口的实现是?CreditLinking cL供的?/p>
public
interface
EmailInterface
{
public
void
sendEmail(ICustomer iCustomer);
public
String getFromEmail();
public
void
setFromEmail(String fromEmail) ;
public
String getPassword();
public
void
setPassword(String password) ;
public
String getSmtpHost() ;
public
void
setSmtpHost(String smtpHost);
public
String getUserId() ;
public
void
setUserId(String userId);
}
Spring 使其保持松散
<?
xml version
=
"
1.0
"
encoding
=
"
UTF-8
"
?>
<!
DOCTYPE beans PUBLIC
"
-//SPRING//DTD BEAN//EN
"
"
http://www.springframework.org/dtd/spring-beans.dtd
"
>
<
beans
>
<
bean id
=
"
createCreditCard
"
-->
define createCreditCard definition
class
=
"
springexample.creditcardaccount.CreateCreditCardAccount
"
>
<
property name
=
"
creditRatingInterface
"
>-->
inject creditRatingInterface dependency via creditRating reference bean
<
ref bean
=
"
creditRating
"
/>
</
property
>
<
property name
=
"
creditLinkingInterface
"
>
"
>-->inject creditLinkingInterface dependency via creditLinking reference bean
<
ref bean
=
"
creditLinking
"
/>
</
property
>
<
property name
=
"
emailInterface
"
>
"
>
"
>-->
inject emailInterface dependency via email reference bean
<
ref bean
=
"
email
"
/>
/
property
>
</
bean
>
<
bean id
=
"
creditLinking
"
class
=
"
springexample.creditlinking.CreditLinking
"
>
<
property name
=
"
url
"
>
<
value
>
http:
//
localhost/creditLinkService</value>-->set url property value
</
property
>
</
bean
>
<
bean id
=
"
creditRating
"
class
=
"
springexample.creditrating.CreditRating
"
>
</
bean
>
<
bean id
=
"
email
"
class
=
"
springexample.email.Email
"
>
<
property name
=
"
smtpHost
"
>
<
value
>
localhost
</
value
>>-->
set smpHtpHost property value
</
property
>
<
property name
=
"
fromEmail
"
>
<
value
>
mycompanyadmin@mycompanyadmin.com
</
value
>
</
property
>
<
property name
=
"
userId
"
>
<
value
>
myuserid
</
value
>
</
property
>
<
property name
=
"
password
"
>
<
value
>
mypassword
</
value
>
</
property
>
</
bean
>
</
beans
>
q行应用E序
ClassPathXmlApplicationContext ctx
=
new
ClassPathXmlApplicationContext(
new
String[]
{
"
springexample-creditaccount.xml
"
}
);
CreateCreditCardAccountInterface creditCardAccount
=
(CreateCreditCardAccountInterface) ctx.getBean(
"
createCreditCard
"
);
]]>
Spring的MVC modelcM于Struts。在多线E服务对象这点上QSpring的ControllercM于Struts ActionQ?font color="#0000ff">只有一个实例处理所有客Lh。然而,我们怿Spring的MVC比vStruts有很多优点,例如Q?
Spring在controllersQJavaBeanQmodels和views提供了一个非常清晰的划分?/font>
Spring的MVC是非常灵zȝ。不像StrutsQ它强制你的Action和Form对象q入固化的层ơ之中(因而你q你用Java的实体承)QSpring MVC完全是基于接口的。而且Q通过插入你自q接口几乎Spring MVC 框架的所有部分都是可配置的。当然我们也提供了方便的cM为实现选择?
Spring MVC是真正的view无关的?/font>你不会被强制使用JSPQ如果你不想那么做的话。你可以使用VelocityQXSLT或其他view技术。如果你惌使用自定义的view机制——例如,你自q模板语言——你可以单实现Spring的View接口q且把它集成q来?
和其他对象一PSpring的Controllers是通过IoC配置?/font>。着使得它们易于试Qƈ且完地和其他由Spring理的对象集成?
Web层变成了业务对象层之?/u>的薄薄一?/font>。这鼓励了好的习惯。Struts和其他专门的web框架让你dC自己的业务对象;Spring提供了你应用E序所有层的集成?
如在Struts 1.1中所见的Q你可以有和你在Spring MVC 应用E序中所需要的一样多的dispatcher servlets?
下面的例子展CZ一个简单的Spring Controller如何能够讉K定义?u>应用E序context?/u>的业务对象。这个controller在它的handleRequest()Ҏ中执行了Google搜烦Q?
q段代码使用的prototype中,IGoogleSearchPort是一个GLUE web services代理Q由Spring FActoryBeanq回。然而,Spring把controller从底层web service库中分离出来。接口可以用普通的Java对象Qtest stubQmock对象或者如下面要讨论的EJB代理实现。这个contorller不包括资源查找;除了支持它的web交互的必要代码之外没有别的什么了?
Springq提供了数据l定QformsQwizards和更复杂的工作流的支持?/p>
而Spring MVC则完全保留着Servlet概念中的requestQresponse和sessionQƈ没有强制建立一个自q概念模型Q当Ӟ他也有很烂的SimpleFormControllerQ但你完全可以把它踢在一旁不)Q也不强刉要FormBean和一堆XML定义?/p>
同时Q它透明完成了与Spring的集成,Multi-action的派发,提供了绑定request数据用的binder{基本API?/p>
所以,如果想简单,使用Spring MVC的原始Ş态是一个很好的Q类gRoR中ActionPack的方案?/p>
推荐使用一个Controller响应一l相兛_作的MultiActionController。同Ӟ虽然一点不喜欢FormController定义的概忉|型,但还是不影响发挥拿来MQ在共性比较明昑台管理模块,定义MultiActionFormControllerQ自动完成某些共同的Form程?br />
2.写给在用其他MVC框架E序员的快速入?br />
也许Q所有程序员都先放下自己框架里的概念模型Q还原回一个JSP/ServletE序员的角度Q思考一个JSP/Servlet框架需要的功能?/p>
0. 配置文g
Spring的配|文仉认ؓWEB-INF/xxxx-servelet.xml?/p>
其中xxx为web.xml中org.springframework.web.servlet.DispatcherServlet的servlet-name?/p>
1. 与Spring集成及IOC
天然兮,由DispatcherServlet完成?/p>
2. Action及Multi-Action 分发
Spring按照配|文件定义的URLQMapping到具体Controllerc,再根据URL里的action= xxx或其他参敎ͼ利用反射调用Controller里对应的ActionҎ?/p>
3. 输入数据l定
Spring提供Binder 通过名字的一一对应反射l定PojoQ也可以直接从request.getParameter()取数据?br /> 如果没有另外加入框架装Q需要手工调用Binder.
4. 输入数据验证
Sping 提供了Validator接口Q而Spring Moduleq整合了Commons-Validaor ?/p>
5. l果数据攑֛View
有个ModelAndView的概念,代表了返回的View名及数据(ModelQ一个Map)。可以用modelAndView.addObject()攑օ数据。当Ӟ也可以直接request.setAttribute()?/p>
6. Interceptor
AOP概念Q其实Servlet里面早有Filter概念Q不qInteceptor可以更灵zȝMappingQ另提供postHandle的插入点
preHandle() handler开工之前?br /> postHandle() hander开工之后,但DispatchServletq没有渲染页面?br /> afterCompletion() 一切完工之后?br />
7. RedirectQForward面及Token防止重复提交?
Spring提供 "redirect:index.jsp", "forward:index.jsp"q样的简写?/p>
Spring Simple Form提供了防止重复提交的机制?/p>
8. 如果想直接编写Responseq回字符? 而不是返回一个View
函数的q回cd设ؓvoidQ用ss装?rendText(response,String text)函数?/p>
3.Spring MVC Multi-action
3.1 基本配置
以上配置按xxx.do?method= list 调用controller的list()Ҏ
不过q要争取早日改ؓWeb2.0式的写法./book/list.htm 要优?book.do?action= list?/p>
其余配置和其他Spring MVC配置差不多,Lbookstore-servlet.xmlQ留意下面几个关键节?br />
4.SpringSide BaseController
l承于Spring的MultiActionController, 对其作了量扩展--主要是对数据l定的扩展,q加了一个SaveMessage函数?/p>
1.Ҏ据绑定的扩展Q?
a.InitBinder() 初始化BinderQ注册日期类q允许数字类为空?/p>
b.对Bind and Validate函数的再包装
本来Spring已有bind函数完成bind and validate, 但这个函C来没有用BindException作返回D是抛出一个ServletException只好自己另外实现一个bindObject()函数?/p>
c.另外E稍扩展了一些函C其更好用?/p>
2.SaveMessage():
如果是redirect的关p,message信息攑֜request.attribute()׃丢失QSaveMessage()其攑֜session?br /> 配合messageFilterQ在渲染面前,把它从session又移回request?
5.后台理通用的BaseManageController
Spring MVC中的SimpleFormController中的交互机制有值得参考的部分Q但其只有一个onSubmit函数不能很好的表达CRUD的语义,所以将两者结合成Multi-ActionFormController是比较好的方法。通过U定命名Q在基类实现list()Qcreate(){函数和默认程Q而在子类实现onList(),onCreate()函数?/p>
目前只是初步l合两者,q有很大的改q空间?/p>
参考了RoR中的命名。BaseManageControllerx照此命名定义基类?/p>
下面列D一下Spring的MVC framework在设计时做出的一些重要的军_Qƈ之和相关的MVC framework如Webwork2或strutsq行Ҏ:
一、Spring的整个MVC配置是基于IOC容器?/font>
与struts或webwork2相比Q这是一个ms有点奇怪的军_Q看一下Spring MVC的配|文Ӟ最先看到的不是action或者formQ而是一些有着特定名字的beanQBean下面的配|是一些简单或有点复杂的属性。我们看到的是机器更Ҏ的数据结构,而不是h更容易理解的元素?/p>
但是q恰恰是Spring的MVC强大的根?因ؓ它的配置是Spring的核心IOC容器的配|,q意味着所有IOC容器的威力都可以在这里展玎ͼ我们可以为所Ʋؓ地对Spring MVCq行扩展和增强,我们可以完成在其它MVC framwork中很多难以想象的d。想扩展新的URL映射方式?要换一个themeResolver或LocalReolver的实现吗?惛_面中显C新cd的View(比如说RDFQ呵呵,一个小U密:xiecc是研I语义网的,虽然成天不务正业Q不写论文,只写八卦)?甚至想直接在Controller里定义AOP?q些对Spring的MVC来说都是菜一?/p>
我没有仔l研I过Webwork2的扩展机Ӟ我知道通过Webwork2的interceptor机制Q可以进行很多的扩展Q甚x一个简单的IOC容器。但不管它有多强大,提供了多扩展点。它的威力都很难和真正的IOC容器相比。而struts的plugin功能则是出名的滥Q虽然它也提供了plugin机制?/p>
Spring采用IOC配置的另一个原因是使Spring的MVC与Spring的IOC容器的整合变得非常的Ҏ。Spring提供了与struts与webwork2的整合,但是q样整合都需要在q行间接的包装,感觉M是很自然。而且q会D一个概念多个配|,webwork2需要在Spring里配|beanQ再配置自己的xwork文g。想象一下吧Q我们的bean直接是一个controller,直接可以完成MVC的所有Q?q是多少爽的感觉?/p>
Rod Johnson采用IOC容器来实现的另一个原因是q会减少好多开发工作量。看一下urlMapping吧,它提供的property本n是一个HashMapQ只有配|完成,我们的bean里的数据p然存在了Q哈哈,好爽吧。不用象struts那样解析XMLQ再把它的内容一一地dHashMap里?/p>
虽然q样的配|会有点怪异Q但假如我们对Spring的IOC容器非常熟悉的话Q会发现它非常的亲切Q也非常的简单?/p>
最后是一个简单的秘密,Spring怎么知道某个bean的配|就是urlMapping?另一个bean的配|就是viewResolver?其实很简单,把所有的bean全部d内存里,然后通过bean的名字或cdLp了。通过名字L是单的getBeanҎQ通过cdL则用了BeanFactoryUtils.beansOfTypeIncludingAncestors的静态方法?/p>
二、Spring提供了明的Model, View概念和相应的数据l构
在Spring里有一个有的数据cd叫做ModelAndViewQ它只是单地把要昄的数据和昄的结果封装在一个类里。但是它却提供了明确的MVC概念Q尤其是model概念的强化,使程序的逻辑变得更清C?/p>
记得以前在Struts里写E序里的时候,Z昄数据l常自己把东西放到HttpSession或HttpServletRequest?或set到form里,虽然不太有用)Q这造成了model概念的模p,而且也导致了struts与JSP面的紧耦合。假如我们要替换成Veloctiy,得另外加一个plugin,因ؓ在velocity里数据是不需要不攑ֈrequest里的?/p>
Webwork2里强调的是与Web framework解耦和它的command模式的简单性,因此在它的action里只有简单的get或setҎQ假如返回数据,也只是简单地q回一个String。当然这L实现有它的好处,但是它E化了model和view的概cRod Johnson认ؓWebwork2里的Action同时包含了Action和Model的职责,q样一个类的职责太多,不是一个很好的设计。当然Jason Carreira不太认同q种观点Q因为Action里的model对象完成可以delegel其它对象。但不管怎样Q这U争论的Ҏ在于Webwork2里E化了model, view甚至web的概c仁者见仁,见智,最后的l果q是看个人喜Ƣ好吧?/p>
三、Spring的Controller是Singleton的,或者是U程不安全的
和Struts一PSpring的Controller是Singleton的,q意味着每个requestq来Q系l都会用原有的instanced理,q样D了两个结?我们不用每次创徏ControllerQ减了对象创徏和垃圾收集的旉;׃只有一个Controller的instanceQ当多个U程调用它的时候,它里面的instance变量不是U程安全的?/p>
q也是Webwork2吹嘘的地方,它的每个Action都是U程安全的。因为每q来一个requestQ它创Z个Action对象。由于现代JDK垃圾攉功能的效率已l不成问题,所以这U创建完一个对象就扔掉的模式也得到了好多h的认可。Rod Johnson甚至以此Z证明J2EE提供的object pool功能是没多大价值的?/p>
但是当h们在吹嘘U程安全怎么怎么重要的时候,我想请问有多h在多情况下需要考虑U程安全?Rod Johnson在分析EJB的时候也提出q其它问题,q不是没有了EJB的线E安全魔法,世界׃灭亡的,大多数情况下Q我们根本不需要考虑U程安全的问题,也不考虑object pool。因为我们大多数情况下不需要保持instance状态?/p>
臛_我写了那么多的struts ActionQ写了那么多的Spring ControllerQ几乎没有碰到需要在instance变量保持状态的问题。当然也许是我写的代码不够多QStruts的设计者Craig R. McClanahan曄说当时他设计struts时有两个条g不成?当时没有试驱动开发的概念;当时JVM的垃圾收集性能太次。假如现在重新设计的话,他也会采用每个request生成一个新对象的设计方法,q样可以解决掉线E安全的问题了?/p>
四、Spring不象Webwork2或tapestry那样去隐藏Servlet相关的元素如HttpServletRequest或HttpServletResponse
q又是一个重要的设计军_。在Webwork2里我们没有HttpServletRequest或者HttpServletResponseQ只有getter, setter或ActionContext里数据,q样的结果导致一个干净的ActionQ一个与Web完全无关的ActionQ一个可以在M环境下独立运行的bean。那么Webwork2的这样一个基于Command模式的ActionI竟l我们带来了什?我想主要有两?
1、它使我们的Action可以非常Ҏ地被试?/p>
2、用户可以在Action里添加业务逻辑Qƈ被其它类重用?/p>
然而仔l跟Spring比较一下,我们׃发现q两点功能所带来的好处其实ƈ不象我们惌的那么显著。Spring的ControllercM可以非常L被测试,看一下spring-mock下面的包吧,它提供的MockHttpServletRequest, MockHttpServletResponseq有其它一些类让测试Controller变得异常L。再看一下Action里的业务逻辑吧,Jason Carreira曄说我们可以尽情地在Webwork2的Action里加业务逻辑Q因为Action是不依赖于Web的。但是有多少人真正往Action里加业务逻辑?大多Ch都会业务逻辑delegateQ委z?l另一个ServicecLManagercR因为我们很清楚Q往Action里加业务逻辑会整个体系的分层架构变得不清晰Q不怎样QWeb层就是Web层,业务层就是业务层Q两者的逻辑混在一hM带来问题的。而且往Action里加业务逻辑会用这个Actioncd得庞大,Webwork2的Action是每个request都创建实例的Q尽带来的性能影响不太大,但ƈ不表C每ơ都要把业务逻辑再new出来Q业务逻辑在大多数的情况下应该是单例的?/p>
不把request和response展现l用户当然还会带来功能上的损失,也许一般的场合Q用用webwork2提供的接口已l够了Q但有时我们必须要知道request和response才能发挥出更大的威力。比如我以前的一个项目里有一个通过递归动态生成的树状l构的页面,在jsp面上显C递归是痛苦或不可能的Q因此我用response直接write出页面,q在spring里很easyQ但在webwork里可能比较难?偶不敢肯定,偶研I得不够深,也许高手是有办法??/p>
五、Spring提供了不错但不够充分的interceptor(拦截?机制
回头看一下strutsQ它在架构里甚至没有l我们提供hook point的机会,我们没有MZ加入自己的interceptor。我们只能通过重蝲struts的RequestProcessorcLq行一Ҏ限的扩展?/p>
CWebwork2Q似乎interceptor一下子成了整个Framework的核心,除了Action的核心部Ӟ其它所有的东西都是interceptor。它的超强的interceptor功能使们扩展整个架构变得非常方便。有人称q种interceptor为AOPQJason Carreira则自豪地宣称q个叫做pragamtic AOP。我不认同这是AOPQ它只是单的interceptor机制。但不管如何Q它的interceptor实有强大的功能?/p>
Spring也提供了它的interceptor机制Q它的HandlerInterceptor三个interceptorҎ:peHandle, postHandle, afterCompletion。分别对应Controller执行前,Controller执行后和page render之后。虽然大多数情况下已l够用,但是从功能上来说昄它没有Webwork2强大。从AOP的角度来看,它没有提供around interceptorQ而只有before与after interceptor。这意味着我们无法在interceptor前后保持状态,最单的情况假如我们要计一个Controller的执行时_我们必须在执行完before后把begintimeq个状态保持住Q再在after里把它调出来Q但是显然这个状态保持会是个问题Q我们不能把它放到instance变量里,因ؓinterceptor不是U程安全的。也讔R过ThreadLocal可以解决q个问题Q但是如此简单的功能要用到这LҎ来处理,昄q个Interceptor本n设计上还是有炚w题的?/p>
六、Spring提供了MultiActionControllerQ它可以在一个类里包含多个Action
q个设计和struts的DispatchAction有点cMQ只不过提供了更灉|的机制。当我们的项目变大的时候,把功能类似的Ҏ攑ֈ同一个Action里完全值得? Webwork2~少q样的机制。假如看一下Spring的源代码Q会发现其实实现MultiActionController的工作量相当的少Q只不过是用反射机制把解析出来的Ҏ名执行一下就完事了。其实Webwork2也完全可以提供这L机制。虽然从设计上来说确实不是很优雅Q但是它实很有用?/p>
七、Spring提供了更多的选择方式
看看Spring里提供的Controller吧,它提供了好多不同的ControllercR要生成Wizard?要专门用于提交form的Controller?要执多个Ҏ的类?Spring提供了丰富的子类来扩展这些选择。当然我们还可以很轻村֜自己扩展q些功能?/p>
再看看Spring的ViewResolver吧, 它提供了无数不同cd的ViewResolver。更重要的是我们自定义我们的面映射方式。看看strtusQ看看webwork2Q都会存在页面与forward name的一层间接{换,我们必须在配|文仉配置好某个字W串(典型的是success)对应的是那个面。但是Spring里我们有了更大的自由度,我们可以采用webwork2的策略,也可以采用更单的{略Q如JSP文g名去掉扩展名的映方法。也许有U映方式很q稚Q但是我觉得它是非常有用的方式,即在大目里?/p>
q有新的扩展?看看Spring Web Flow吧,它是SpringFramework的子目。它Z长串的基于页面流的Wizard面提供了可配置的实现方式。在Spring 1.3里,它将是SpringFramework的一部分?/p>
八、Spring的tag
管Spring的tag数量上少得可怜,但它却是_ֿ设计的。它的目标很?让美工可以轻村֜~辑面。因为在Spring的页面里Text仍然是TextQcheckbox仍然是CheckBoxQ而不象在struts或webwork2中的Tag。它只是用Springbind对输入内容进行了一下包装。所以尽页面显CZ码上会比Webwork2多,但这l对是有价值的?/p>
在接下来的几章里Q我会分析一下Spring是如何让我们的Web应用不需要知道ApplicationContextp够访问IOC容器的,然后会对Spring的设计和执行q程q行单的源码分析Q然后给出几个扩展Spring MVC的方法?/p>
DispatcherServlet
DispathcerServlet的角色就好像是一个Q意门Q他位于spring mvc?入口"惛_那跟他说对了。但是要使用L门,您必需先安上他。要怎么按上? DispatcherServlet本n其实是一个ServletQ所以我们要做的事就是在web.xml中布|他。就如同一般Servlet布v的方式一P描述servlet的名字和cdQ再l他一个mapping描述适用的网c?/p>