虚拟访谈:Struts 1.x一路走好

前段时间,Struts 1.x正式宣布退出舞台,作为一个历史悠久的MVC框架,Struts 1.x影响了不少的开发者,甚至可以说,很多人就是通过Struts学习和认识MVC的。为了纪念这位“先驱”,同时帮助那些仍在使用Struts 1.x框架的开发者更好地过渡到其他MVC框架,InfoQ邀请了几位专家:

\
  • 李锟,知名技术专家,资深架构师,在REST等领域颇有建树。出版过《REST实战》、《Ajax实战》等多部译作。\
  • 张逸,一个怀揣梦想的架构师,沉迷于设计之美,游走于.NET与Java之间,但更偏好关注架构与设计本质,著译作包括《软件设计精要与模式》、《WCF服务编程》等。\
  • 张龙,热衷于编程,乐于分享,对Java轻量级框架有一定研究,工作流领域研究者,资深培训讲师。翻译出版了《Spring高级程序设计》、《设计原本》等书籍。\

大家一起畅谈他们印象中的Struts 1.x,以及如何选择框架等等问题。

\

1. Struts是最早的MVC框架之一,影响了很多人,你是否还记得最早接触到它时,给你留下的印象是什么?

\
李锟:我在2000年就开始做Java Web开发,使用的技术是JSP+JavaBean。很快我们就遇到了代码重用难、维护不便的问题。我在网上找到一篇文章,介绍了Java Web开发的两种模式Model 1和Model 2。我理解了什么是Model 2和Web MVC设计模式,然后又知道Struts 1.x。当时我对这个框架很感兴趣,花了一些时间学习。不过因为工作变化,当时没有用起来。

\2003年,我在一家公司做电子政务类的项目开发,公司创始人开发了一套基于XMLHttp和XML模板的快速框架。虽然我们开发的应用只支持IE,但是可以说那个时候我们就已经在做Ajax开发了。电子政务类的项目,经常要开发比较复杂的Tree、Data Grid等Web前端控件。很显然Struts 1.x这种瘦客户端的开发框架对此帮不上什么忙,我们需要的是富客户端开发框架,甚至是一个完全依赖JavaScript的开发框架。我们当时对Struts 1.x的看法是:中看不中用,开发效率低下(相对我们自己的框架),已经过时了。

\后来我在工作中陆续使用过Struts 1.x和Struts 2.x。我曾经把一个开源的基于Struts 1.x的自助式广告联盟应用移植到Spring MVC,还基于Struts 2.x做过网站开发。Struts 1.x的主要问题是框架的侵入性太大,不利于代码重用和单元测试。Struts 2.x确实进步很大,完全基于POJO,学习曲线低了很多,还支持零配置(不需要XML配置,甚至也不需要Annotation)。尽管如此,Struts 2.x仍然明显落后于时代。


  • Struts 2.x这一类老牌Web MVC开发框架仅能用于开发瘦客户端应用,无法用来开发对于交互体验要求更高的应用。\
  • Struts 2.x的REST插件对REST的支持非常差,连子资源都不支持,只能当作一个玩具。\
\和我们在2004年时的预测相同,目前富客户端+RESTful Web Services已经大行其道,先是各种基于JavaScript的One Page开发框架,接下来是移动Web应用的爆发。我预测Struts 2.x在大约3年之后也会走向自己的终点。事实上Struts 2.x从2007年到现在几乎没有进步,其灵魂人物Rickard Oberg(创造了WebWork和Struts 2.x)早已经离去。
张逸:从业15年来,我主要参与的开发工作除了早期的Windows Form应用开发外,主要还是集中在后端。用分层的角度来说,即工作在数据层、领域层以及服务层。虽然早已知道Struts的大名,甚至了解到所谓Struts+Spring+Hibernate几乎成为了Java企业开发的标配,却一直没有机会使用Struts。我当时工作的项目主要还是在微软的.NET平台上,经历了从ASP到ASP.NET,再到ASP.NET MVC的过程。在使用ASP时,我很质疑那种业务代码与表现代码混杂在一起的开发方式;而在最初拥抱ASP.NET时,我认为这种Code-Behind会是一种良好的职责分离。然而,ASP.NET在灵活性或扩展性方面带来的约束,使得它越来越不适合富客户端的开发了。于是,才有了借鉴Ruby On Rails思想的ASP.NET MVC出现。或许我的回答偏题了,但我想借ASP的这种发展来看待此次Struts 1.x退出历史舞台的事件,那就是任何产品都会步入晚年的衰落期,跟不上技术的发展,必然会被淘汰,没有什么好奇怪的。\\
张龙:我记得第一次使用Struts框架是在2005年,那时还在上海上学,在一家公司做兼职项目开发时用到的这个框架。在使用这个框架之前我仅仅对JSP、Servlet有过一些经验,对于MVC模式也只限于理论上的了解。当时在学校做一些项目的时候用得比较多的还是基于Model 2的开发模式,即JSP+Servlet。我印象特别深的是在开始使用Struts框架时完全感觉无从下手,一下子觉得变得太复杂了,一段很简单的表单提交逻辑就涉及到Struts的各种标签、FormBean、Action,当然还有内容颇为庞杂的struts-config.xml文件。当时一边写心里一边在想,为什么要这么复杂,JSP+Servlet就可以轻松搞定的事情为什么要写这么多类,还有那个复杂的配置文件,一时半会儿真是无法理解。好在随着项目的不断进行,当逻辑变得越来越复杂,类文件数量变得越来越多时我才逐渐感受到Struts框架带给我们的好处:强迫开发人员将不同层次的代码写到不同的文件中,通过配置文件就可以清晰了解整个项目的逻辑运转过程,这个过程我大概花了半个月左右的时间才算是比较透彻地理解清楚了。我觉得很多学习Struts框架的人一开始的想法应该与我有很多相似之处。Struts框架可以说是Java Web开发领域的一个里程碑,是最早的MVC框架之一,影响了一代Java Web开发人员这种说法也不算过。
\

2. Struts 1.x即将走完最后的历程,对于那些仍在使用它的系统,你有什么建议?如果要升级,有几个备选方案,例如Struts 2.x、Spring MVC等等,你会如何选择?

\
李锟:我建议选择迁移到Spring MVC,我在这方面有一些实战经验。Spring MVC既支持Struts 1.x的开发方式(一个Action是一个Singleton对象,里面有很多方法),也支持WebWork那种基于Command模式的开发方式(一个Action是一个Prototype对象,只有一个方法)。从Struts 1.x移植到Spring MVC的难度不会很大,另外由于Spring MVC仍然在持续发展,并且能够较好地支持REST开发,在我看来应该选择哪个框架是很明显的。
张逸:奇怪的是,虽然在早期我不曾有机会使用Struts 1.x,然而我现在正在工作的一个大型项目,因为其漫长的历史,一部分Web前端使用的正好是Struts 1.x。对于这种正在使用它的系统,若要说有何建议,简言之,还是需要在决策时视情况而定。在我们当前项目的一个子系统中,Struts 1.x是与Spring MVC 2.0共存的;而在另一个子系统中,又存在Struts 2.x与Spring MVC 3.x共存的情况。从架构的一致性来看,这是很不合理的;然而就项目的真实情况,我又认为这种现象未尝不可。迁移的成本往往是昂贵的,尤其对于遗留系统而言,若没有覆盖率极高的验收测试,盲目地为了追求架构一致性进行迁移,反而会引入新的问题。这就需要权衡迁移的成本和迁移得到的好处。在Java平台下,可供选择的成熟Web框架并不多,Struts 2.x以及Spring MVC相较于Struts 1.x而言,主要还是体现在模式上的区别,属于侵入性更小、架构更为简单的框架。相对于升级,我更倾向于保留原有框架,对于新增的功能则可以引入更新的框架。若因为种种原因硬要升级,我更倾向于选择Spring MVC,一方面它与Spring框架的集成度更好,学习曲线低;同时它对于Struts 1.x实现方式的固有支持,会使得迁移的成本会降低。最重要的一点是Spring MVC目前还保有一定程度的活力,它的版本还在演化中;相对而言,Struts似乎已经失去活力了。

\若抛开这些成熟的Web框架不谈,我的建议是不妨试试Java平台下的其他框架,例如jRails,Spring Roo、Apach Wicket或者Play。若想继续工作在Spring的技术栈下,Spring Roo会是一个有趣的选择。事实上,你可以认为它是Spring所要力推的下一代Web框架,如果你不想重蹈Struts 1.x的覆辙,可以在决策时冒着风险给予提前尝鲜的机会。Play框架是基于Java和Scala开发的Web框架,它似乎更偏重于建造可伸缩性的Web框架。此外,它的安全模块、持久化支持(包括对NoSQL与Big Data的支持)、RESTful以及Mobile的支持,使得它更适合开发当今的Web应用程序。

张龙:前不久Apache宣布Struts将EOL,其实我个人认为这对于尚在使用Struts进行开发的项目来说不算是世界末日,毕竟Struts从第一个版本到现在已经经过了很多年的发展,框架代码也已经变得非常成熟,而且由于开源,开发人员完全可以通过源代码了解Struts的实现原理,并没有什么秘密可言,而且Struts相关的文档与资料也已经非常多了,所以我觉得并不会对现有项目造成太大影响。何况对于那些采用SAP进行二次开发的企业来说,由于标准代码就是基于Struts框架的,因此采用Struts也是不二之选。从这个角度来说,我认为Struts的EOL只是随着软件开发发展的一种正常现象,毕竟十多年前的设计与架构现在已经无法更好满足软件开发之所需了,也算是软件生命周期的一种必然结果。

\如果是新的项目,我想选择Struts进行开发的企业应该还是少数,因为现在已经有了更多、更好的选择。比如说Struts2、Spring MVC等。我对于这两个框架都有一定的使用经验,也开发过不少项目。我是个技术实用主义者,其实我个人认为无论是Struts2还是Spring MVC都是顺应新时代的软件开发潮流而产生的,在我个人看来,这两个框架在设计哲学上存在较大的差异,但从实际项目开发的角度来说,无论哪一个框架都是可以胜任的。众所周知,Struts2来源于Opensymphony(很遗憾,Opensymphony已经于一年前关闭了,其下的众多项目也被独立出去单独开发了)的WebWork,它与Struts没有任何关系,只是借助于当时非常流行的Struts这个名字而已,实质上还是完全沿用了WebWork的设计思想与XWork这个微内核、基于命令模式的框架,另外在ValueStack和标签库上做了一些增强和改进。而Spring MVC则是一个后起之秀,并且在Spring的大旗下发展迅猛。从设计角度来说,Struts2采用了基于POJO的思想,摒弃了Struts的FormBean,这样每一个Action都是一个有状态的对象,因此需要针对每个请求创建一个新的Action实例。另外由于采用了OGNL,这使得Struts2的标签库变得非常灵活和强大,又由于Struts2的插件设计思想,我们可以非常轻松地采用已有的插件和开发自己的插件扩展Struts2的功能,这使得Struts2的可扩展性变得非常强,目前Struts2的官网上已经有了几十种常见插件供我们使用,比如Spring集成、注解插件、REST插件、与一些前端框架的集成等,对我们的开发起到了非常大的帮助作用。

\Spring MVC的设计思想与Struts2截然不同,它采取的策略有些类似于传统的Servlet,即每一个Controller都是无状态的单例,客户端参数的传递是通过自定义方法参数得到的,而且相对于Struts2的设计来说,Spring MVC的设计更加灵活,比如说我们可以自定义各种各样的方法、可以通过各种方式匹配客户端的请求,而不像Struts2那样只能通过URL来匹配,但这也带来一个问题,就是开发人员可能每个人使用的方式都不一样,为项目的后期管理和维护带来一定的问题。因此,在我所经历的Spring MVC项目中,都会提前定义好各种规范和契约,使得大家遵循共同的访问模式,这样比较有利于项目的统一。

\从我个人角度来说,我觉得选择Struts2还是Spring MVC还是看项目组开发人员的技术掌握程度,或是想学一些新的技术这个方面的考量,毕竟二者都非常成熟,而且都与Spring有着良好的集成。此外要提的一点是,Spring MVC提倡基于注解的配置,Struts2默认使用XML(当然也可以通过插件使用基于注解的配置),这个就要看项目组成员的想法了,有些人喜欢配置文件,有些人喜欢注解,我们不能说哪个好哪个不好,只是一种风格选择而已。

\

3. 经常会有框架或软件结束生命周期,不再进行维护,这对使用它的用户多多少少带来了一些困扰 ,能否聊聊您在项目最初进行选择时的一些经验之谈。

\
李锟:我的经验是尽量选择一些基于POJO设计的开发框架,这样代码重用和单元测试都更容易。另外尽量选择学习曲线低的开发框架,当然熟练掌握一种复杂的框架或者技术可以作为炫耀的资本,但是如果你处在一个团队之中(而不是单打独斗),引入这样的框架很可能会极大增加团队成员的负担,从而极大增加开发和维护的成本。好的开发框架应该尽量做到透明,应用程序运行于其中,程序员主要关注的应该是实现应用自身的业务逻辑,而不是花很多精力与框架本身搏斗。EJB 2.0问题非常多,所以现在已经没人用了。进入成本和退出成本都很高的开发框架,哪怕再强大神奇,我也不会选择的。KISS是一个很好的设计原则,也可以作为开发框架的选择原则。
张逸:对于框架的选择,我比较偏重于框架的简单性和无侵入性这两个特点。简单性可以保证我们快速地理解框架的架构,并能够正确地使用它;无侵入性则使得我们可以避免所谓“供应商锁定”的反模式,在需要迁移框架时,可以尽快摆脱原有框架的约束。当然,这种选择总要结合项目需求,根据风险对各种质量属性进行综合权衡,方能做出合理的设计决策。因此,我会将这两个特点看做是重要的衡量指标,但并非绝对。在一定程度上,我们还可以通过更好的架构设计来规避对框架的依赖,例如通过好的分层设计,或者引入防腐层隔离对框架的依赖。以Struts 1.x而言,只要我们避免在Action中引入业务逻辑,选用新Web框架的成本就会更低一些。同时,保证足够的测试覆盖率是必要的,尤其是足够覆盖率的单元测试与集成测试,它常常可以放缓系统衰老的脚步。对于旧系统的维护或重构而言,测试覆盖率是进行改造的良好基石。
张龙:在项目技术选型时,我还是比较激进的。总是希望在新的项目中让大家能多学到一些东西、新的技术或是新的框架等,当然这是在保证项目按时交付的前提下需要考量的因素。但有一点我是比较在意的,那就是所选择的技术是否已经有了一些成功的案例,资料文档是否比较完备(我们不能要求每个人都仔细研读所用开源项目的源代码),而且项目组中需要有人提前研究相应的框架,这样在遇到问题时才能提出相应的解决方案。无论选择什么技术与框架,需要有人提前研究并给大家进行较为详尽的介绍,同时还要与相关的技术框架进行一些横向对比。至于软件结束生命周期,很多时候是我们无法事先预料到的。但我想如果某个软件结束生命周期,那说明会有更多、更好用的软件出现,这也会给我们带来更大的选择,但要是对现有的软件进行升级可不是一件容易的事情,比如将基于Struts的项目升级到Struts2就是个极其艰巨的任务,这时还是要仔细权衡了,看看是否继续沿用已有的框架,然后在新的项目中采用其他方案,这并没有统一的解决思路,还是要看实际的项目与业务情况。
\

4. 随着像Backbone.js这样的前端MVC框架的流行,Struts这样的服务器端MVC的作用似乎有所减弱,您觉得MVC逻辑“前移”会是今后的发展趋势么?

\
李锟:MVC逻辑前移肯定是今后的发展趋势。其实在2005年Ajax和RIA技术兴起时,Web MVC这种瘦客户端应用的设计模式就已经过时了。

\当然,Web应用的范围极为广泛。如果考虑到SEO,还是有很多应用必须要做成瘦客户端形式的,所以Web MVC开发框架仍然会存在很多年。但是对于移动应用来说,Web MVC肯定已经过时了。注意这里我说的是Web MVC,而不是MVC。在移动应用中,MVC作为一种基础设计模式,其实现已经完全前移到客户端,而服务器端则简化为单纯的数据提供者,通过RESTful Web Services为客户端提供数据。

张逸:我完全赞同这一点。在我参与的上一个项目中,对于服务端的Web层而言,几乎就成为了一个Controller+JSON+REST的组合,MVC中的M被JSON或资源所替代,V则干脆消失了,由Controller来负责必要的服务端验证,并完成HTTP请求的路由功能,其余的前端逻辑都交由我们当初选择的ExtJS了。

\这种设计是完全合理的。但我仍然要说明一点的是,这种设计由于加大了前端的复杂度,因而需要我们更加关注前端的代码质量。传统开发要求的关注点分离、松耦合与高内聚原则同样适用于这样的前端代码。虽然不一定要提倡前端代码的测试驱动开发,但至少要保证这些代码具有足够的测试覆盖率。例如,我们可以为Javascript(或者jQuery)引入Jasmine,QUnit等测试框架。在我们曾经参与的一个项目中,由最初只支持一个品牌,增强到支持多个品牌的需求变化,这其中需要涉及到对大量前端代码的复用。由于之前的设计并未考虑到多品牌的支持,因而需要重构前端代码,以达成复用的目的。如果没有足够的测试覆盖率,以及良好的职责分离,要做到这一点的难度不言而喻。

张龙:Backbone我在项目中使用过,其实我觉得前端MVC框架与Spring MVC这样的后端MVC框架并不矛盾。他们尝试解决的问题和面向的对象是不同的,一个是如何实现前端的解耦,一个是如何实现后端的解耦,二者肯定会共存,并且都有各自的用武之地。毕竟,前端MVC需要大量的JavaScript、CSS代码,是不是每个项目都需要做成这样呢?相信每个人心中都有自己的答案。
\

此外,大家还就未来的开发框架做了些畅想,李锟对开发框架提出了一些要求:

\
  • 继续支持Web MVC模式仍然是基础功能,至少不能比Struts 2.x、Ruby on Rails这样的传统开发框架做得差。\
  • 约定先于配置,对于大多数开发场景尽量做到零配置。\
  • 模块化、插件化、更好的可定制性,开发者可以在核心模块的基础上,根据自己需要添加不同的组件,而不是要么全有、要么全无。\
  • 低成本。更轻量级、学习曲线更低、性能更好、更容易配置和维护。\
  • 很好地支持REST开发,不仅支持开发RESTful WebService,还支持开发RESTful WebApp。\
  • 集成并提供大量Web前端的开发控件,并且能与服务器端组件建立流畅的交互流程。\

他认为今后必会出现面向移动Web应用(富客户端)开发的一站式框架,从Web前端一直到持久层完全打通,把客户端的MVC和服务器端的MVC结合在一起,其中有5个组成部分,客户端有MVC,服务器端不再有V,只有MC。

\
目前客户端MVC开发框架已经非常多了,很多支持MVC的JS框架,Flash也有Pure MVC等多种选择。但是它们与服务器端的MVC开发框架并没有做很深入的整合,这样又出现了当年Struts、Spring、Hibernate各自为战的局面。初学者的入门门槛很高。2005年Ruby on Rails横空出世之后,自以为牛X的SSH立即风光不再。大家恍然大悟,其实Web开发应该这样做。复杂不是王道,简化才是王道。
\

张逸非常认同李锟提到的这个模式:

\
许多模式事实上都是从MVC模式衍生而来,例如MVP等。此时,MVC可以作为核心模式的一个名词。应该为那些变种的模式命名,并给出最佳实践,从而表达特定的含义。
\

他建议将这种模式命名为MC2MVC,或者RC2MVC。有个“2”,就表示从服务端到客户端的意思。至于RC2MVC,则是为了强调服务端提供的“资源”,而非传统意义上的模型。

\

笔者也同样非常认同这种模式,但在具体的框架实现上稍有不同:

\
我相信MVC前移这个一定是趋势,而且JS的框架现在也越来越强大了,后端服务器上的MVC的V将渐渐地变为REST接口,为前端MVC提供数据。但是我并不希望再出现一个类似Rails的一站式框架,从前端到后端统统囊括在内。Rails在刚诞生的时候的确引起了不小的轰动,但是时至今日,它的问题也是非常的多,比如默认开启了太多的功能,还有在非Web领域方面的应用问题,Robbin的那篇 《Ruby社区应该去Rails化了》已经写的非常清楚了。我更希望能看到多个框架分别负责前端MVC,后端的MC,各自做精做好,然后再有一个粘合剂框架将前后串联起来。大家都能独立发展,可以很方便地替换框架,当然,这也是要求能做到很高的非侵入性。
\

各位读者,不知您是否也有一些话想对Struts 1.x说?您对今后的框架又有何想法呢?不妨一起探讨一下。

\

『号外』:JavaOne 2013大会将于7月22–25日在上海世博中心举行,内容涵盖使用Java SE构建现代应用程序、打造针对下一代智能设备的移动和嵌入式Java应用程序、编制基于Java EE的复杂企业解决方案以及在云环境中安全、无缝地构建和部署业务应用程序等,报名或查看详情请点击。

你可能感兴趣的:(虚拟访谈:Struts 1.x一路走好)