?
特性比较
Action classes | Struts要求Action类继承一个抽象类. 这也说明了Struts的一个常见问题: 针对抽象类编程而不是接口. | Action必需实现webwork.Action接口. 还有其他接口可以实现其他服务, 如保存错误信息, 获取本地化文本等. ActionSupport类实现了其中的一些接口, 也可以用作基类. WebWork全部针对接口编程, 这样很容易插入你自己的实现. | 与WebWork 1.x相同, Action必需实现com.opensymphony.xwork.Action接口, 还有一系列接口用于其他服务. WebWork2提供ActionSupport 实现这些接口. |
线程模型 | Struts的Action必须是线程安全的, 因为它仅使用一个示例处理全部请求. 这一限制导致Struts的Action执行过程中使用的任何资源必须是线程安全的或同步访问. | WebWork的Action每一个请求使用一个实例, 一次就不存在线程安全问题. 实践中, 每一次请求Servlet容器都会生成许多将被丢弃的对象, 多一个或几个对象并没有证明会带来性能问题或垃圾收集问题. | 同上 |
对Servlet的依赖性 | Struts的Actions依赖于Servlets, 因为执行时使用(获取)了ServletRequest和ServletResponse(而不是HttpServletRequest和HttpServletResponse). 绑定Servlets(虽然不是HttpServlet)实际上就与Servlet容器绑定了, 而这种依赖关系并不需要. 例如, Servlet可以在Web环境之外运行, 但JMS就不能. | WebWork的Action没有绑定Web或其他任何容器. WebWork的action可以选择从ActionContext中获取request和response, 但这不是必须的并且仅当绝对必要时才是用, 这并不会与Web容器绑定. | 同上 |
可测试性 | 已经有许多测试Struts应用的策略, 但主要障碍实际是Struts的Action与Web紧密的绑定在一起(获取Request和Response对象). 着导致人们经常在一个容器中测试Sstruts的Action, 这样做既缓慢而又无法进行单元测试. 有一个Junit的扩展包 : Struts TestCase (http://strutstestcase.sourceforge.net/ ) | WebWork的action可以通过实例化action, 设置属性并执行的方式进行测试 | 同上, 但重点在于反转控制(Inversion of Control)让测试变得更简单, 你可以在测试中设置一个实现服务接口的Mock对象进行测试, 而不需要设置服务注册表或使用单件(static singleton) |
FormBeans | Struts需要为每个表单使用FormBean, 这产生了大量的多余的类或者不得不使用DynaBean, 而这恰恰是这一限制的产物 | WebWork 1.x允许直接使用Action的属性(也就是标准的Javabean属性), 属性可以包含丰富的对象类型甚至可以有自己的属性, 而这些属性都可以从Web页面中访问. WebWork也支持FormBean模式, 在"WW1:Populate Form Bean and access its value "中有关一这部分的介绍 | WebWork 2支持WebWork 1中的特性, 还加入了ModelDriven的Actions, 它允许使用丰富的对象类型或域对象作为form bean, 可以在Web页面中直接访问它的属性, 这要好于作为活动属性的子属性进行访问. |
表达式语言 | Struts 1.1集成了JSTL, 因此它使用JSTL EL. 该语言支持基本的对象图遍历, 但对集合和索引的属性的支持要弱一些. | WebWork 1.x拥有自己的表达式语言用以访问值栈. 对集合以及索引属性的支持很基本但很好. WebWork也可以直接与JSTL共同使用, 参见WW1:Using JSTL seamlessly with WebWork | WebWork 2使用XW:Ognl , 这是一个非常强大的表达式语言, 也可以访问值栈. Ognl对集合和索引属性的支持非常强大. Ognl还支持一些强大的特性如投射(projections, 对集合的每一个元素调用同一个方法并使用结果创建一个新的集合), 挑选(selections, 使用一个选择表达式过滤集合并返回一个子集), 列表构造和lambda表达式 (简化功能). Ognl还能访问静态方法, 静态字段和构造方法. WebWork2也能使用JSTL, 参见WW1:Using JSTL seamlessly with WebWork |
将值绑定到视图 | Struts使用标准的JSP将对象绑定到pageContext, 这使得视图与formBean紧密耦合 | WebWork设置了值栈, WebWork标签库可以从中十分灵活的动态查找所需的值, 而不需要将视图与数据类型紧密耦合. 这样就可以在很大的范围内复用视图. | 同上 |
类型转换 | Struts的FormBeans属性通常都是字符串. Struts使用Commons-Beanutils进行类型转换. 每个类使用一个转换器, 但不允许为每个实例配置不同的转换器. 获取一个有意义的类型转换错误并显示给用户也是很难做到的. | WebWork 1.x使用PropertyEditors进行类型转换. PropertyEditors针对类型而不是Action, 但字段错误信息可以加到活动的字段信息表中并自动显示给用户. | WebWork2使用Ognl进行类型转换, 并为基本类型提供了转换器. 类型转换缺省情况下使用上述转换器, 但也可以为每个类的每个字段指定转换器. 类型转换错误也有缺省错误信息但可以使用本地化机制设置每个字段的信息, 字段错误信息可以加到活动的字段信息表中并显示给用户. |
前/后处理模式 | 必须创建一个继承基类Action的类来作为Action前/后处理的代理, 这将导致类继承层次过深, 也可能因为单继承的限制而无能为力WW:Comparison to Struts#1 | 类继承 | WebWork 2允许使用截取器模块化前/后处理. 拦截器可以通过配置动态添加, 两者之间没有任何耦合. |
校验 | Struts调用FormBean的validate()方法. Struts用户通常使用Commons Validation进行校验. 我对此不太了解,
因此仅提出几个问题: ? 由于FormBean属性一般都是字符串, 某些校验方法是否会重复或无法做到? ? Commons Validation是否能为同一个类设置不同的校验环境? (我已被告知可以做到, 这是好事) ? Commons Validation能否使用为对象属性类定义的校验方式对子对象(sub-objects)进行校验? |
WebWork1.x调用Action的 validate()方法, 你可以编写代码校验, 也可以调用外部校验框架(这显然与Sstruts相同) | WebWork2可以使用WebWork1.x和Struts的validate()方法, 还可以使用XW:校验框架 , 它由一个XWork截取器激活. Xwork校验框架允许用XML格式编写校验器, 可以为每个类提供一个缺省校验器并在不同的校验环境中使用定制校验器.Xwork校验框架由一个截取器激活因此与Action类完全解藕. 还可以使用VisitorFieldValidator将校验处理连接到子属性(sub-properties, [与上文提到的子对象相同 ). |
对Action执行过程的控制 | 以我的了解, Struts设置一个Action对象, 而你对执行的顺序几乎无法控制. 要改变这一点, 我认为 需要编写自己的Servlet来自行处理分发(dispatching) | 由ActionFactory链控制Action创建和初始化的过程, 但需要编写一个类 | 在这以问题上WebWork 2的截取器栈十分有用. 设置Action的各方面功能都被转移到截取器中实现(如设置参数, 校验等), 因此你可以依据截取器的功能控制每一个Action的执行顺序. 例如你可能希望你的IOC框架在request参数设置之前完成Action配置, 反之亦然 - 也可以使用截取器栈对每个包或每个类进行控制. |
?
参考资料
?
Apache Struts 2即是之前大家所熟知的WebWork 2。在经历了几年的各自发展后,WebWork和Struts社区决定合二为一,也即是Struts 2
Action 类:
Struts1要求Action类继承一个抽象基类。Struts1的一个普遍问题是使用抽象类编程而不是接口。
Struts 2 Action类可以实现一个Action接口,也可实现其他接口,使可选和定制的服务成为可能。Struts2提供一个ActionSupport基类去实现 常用的接口。Action接口不是必须的,任何有execute标识的POJO对象都可以用作Struts2的Action对象。
线程模式:
Struts1 Action是单例模式并且必须是线程安全的,因为仅有Action的一个实例来处理所有的请求。单例策略限制了Struts1 Action能作的事,并且要在开发时特别小心。Action资源必须是线程安全的或同步的。
Struts2 Action对象为每一个请求产生一个实例,因此没有线程安全问题。(实际上,servlet容器给每个请求产生许多可丢弃的对象,并且不会导致性能和垃圾回收问题)
Servlet 依赖:
Struts1 Action 依赖于Servlet API ,因为当一个Action被调用时HttpServletRequest 和 HttpServletResponse 被传递给execute方法。
Struts 2 Action不依赖于容器,允许Action脱离容器单独被测试。如果需要,Struts2 Action仍然可以访问初始的request和response。但是,其他的元素减少或者消除了直接访问HttpServetRequest 和 HttpServletResponse的必要性。
可测性:
测试Struts1 Action的一个主要问题是execute方法暴露了servlet API(这使得测试要依赖于容器)。一个第三方扩展--Struts TestCase--提供了一套Struts1的模拟对象(来进行测试)。
Struts 2 Action可以通过初始化、设置属性、调用方法来测试,“依赖注入”支持也使测试更容易。
捕获输入:
Struts1 使用ActionForm对象捕获输入。所有的ActionForm必须继承一个基类。因为其他JavaBean不能用作ActionForm,开发者经常创建多余的类捕获输入。动态Bean(DynaBeans)可以作为创建传统ActionForm的选择,但是,开发者可能是在重新描述(创建)已经存在的JavaBean(仍然会导致有冗余的javabean)。
Struts 2直接使用Action属性作为输入属性,消除了对第二个输入对象的需求。输入属性可能是有自己(子)属性的rich对象类型。Action属性能够通过web页面上的taglibs访问。Struts2也支持ActionForm模式。rich对象类型,包括业务对象,能够用作输入/输出对象。这种ModelDriven 特性简化了taglib对POJO输入对象的引用。
表达式语言:
Struts1 整合了JSTL,因此使用JSTL EL。这种EL有基本对象图遍历,但是对集合和索引属性的支持很弱。
Struts2可以使用JSTL,但是也支持一个更强大和灵活的表达式语言--"Object Graph Notation Language" (OGNL).
绑定值到页面(view):
Struts 1使用标准JSP机制把对象绑定到页面中来访问。
Struts 2 使用 "ValueStack"技术,使taglib能够访问值而不需要把你的页面(view)和对象绑定起来。ValueStack策略允许通过一系列名称相同但类型不同的属性重用页面(view)。
类型转换:
Struts 1 ActionForm 属性通常都是String类型。Struts1使用Commons-Beanutils进行类型转换。每个类一个转换器,对每一个实例来说是不可配置的。
Struts2 使用OGNL进行类型转换。提供基本和常用对象的转换器。
校验:
Struts 1支持在ActionForm的validate方法中手动校验,或者通过Commons Validator的扩展来校验。同一个类可以有不同的校验内容,但不能校验子对象。
Struts2支持通过validate方法和XWork校验框架来进行校验。XWork校验框架使用为属性类类型定义的校验和内容校验,来支持chain校验子属性
Action执行的控制:
Struts1支持每一个模块有单独的Request Processors(生命周期),但是模块中的所有Action必须共享相同的生命周期。
Struts2支持通过拦截器堆栈(Interceptor Stacks)为每一个Action创建不同的生命周期。堆栈能够根据需要和不同的Action一起使用。
Struts作为MVC 2的Web框架,自推出以来不断受到开发者的追捧,得到用广泛的应用。作为最成功的Web框架,Struts自然拥有众多的优点