一、简介 本 文与其它典型的Java文章有所不同,这主要体现在两个方面。首先,我们没有深入讨论有关于一些API或优秀工具的细节,而是提供了使用敏捷方法和普通 Java对象(POJO)构建企业级Java应用程序的一个指南。其次,本文中涉及到大量的从概念到工程发布等多方面的基本内容。因此,为了简洁起见,本 文中仅提供了极少的代码摘录;然而,本文还提供了一个基于Spring,Hibernate,Junit和Ant构建的完全可运行的示例时间表应用程序 (并有相应的源代码)供您参考。 现在,让我们言归正传。 二、敏捷宣言 在2001年,17位软件专家(包括Martin Fowler,Kent Beck和Jon Kern)聚集到一起共同探讨有关软件开发的轻量级途径;最终,他们联合定义了术语“敏捷”并发出了“敏捷软件开发宣言”—为这些敏捷方法提供了一组参考值和原则。 术 语“敏捷”中融入了大范围的多种方法;其中一些包括极限编程(XP),Scrum,特征驱动开发,敏捷建模以及Crystal。而且,这其中的许多方法都 倾向于至少包括过程和建模两个方面(因为它们经常联系在一起);接下来,我们将逐一展开讨论。而有关敏捷宣言和各种敏捷方法的更多细节,请访问 agilemanifesto.org和agilealliance.org网站。 三、敏捷过程 一 种最容易理解的敏捷过程就是Scrum。尽管XP在整个敏捷社区似乎更为引人注目,但是它较之于Scrum要更复杂些。不过,这两者却是高度互补的,因为 XP提供一组优秀的工程实践,而Scrum则更多地强调产品/工程管理。事实上,最近,我更倾向于推荐首先基于Scrum进行“敏捷”开发,然后每次添加 一项XP实践,这是因为完全基于XP进行开发对于许多组织来说还有些太冒然,并且要求他们对于许多工程的开发要作好充分的思想准备。 那么,Scrum是如何工作的呢?很简单。我们只需提供相应于产品订货(BACKLOG)中的一个应用程序的新特征或改变请求的一个列表即可。在我们的示例应用程序TimeExpression中,这些包括: ◆按小时工资制的雇员能够签入到一个Web应用程序并且输入对于某一周他们每天的工作小时数。 ◆该雇员的经理必须同意这个时间表。 ◆在同意/否定了一个时间表之后,把通知发送给该雇员并指示该时间表的更新状态。 ◆等等…… 之 后,我们只要按照最高优先级特征,把它们移动到一个sprint订货表中,并且通过一个月(或更短时间内)的反复工作来实现它们(称为 “sprint”),并且继续这种以月为周期的sprint直到实现所有的特征。每一个sprint(或迭代)都包含完整的软件生命周期—也即:详细的要 求/分析,设计,编码,单元/接受测试,以及成熟产品的发布。Scrum还建议,在每一个sprint的开始举行一次计划碰头会,而在该sprint的完 成之时进行一次回顾来讨论已经取得的教训或在随后的sprint中要实现的特征。除此之外,我们还要举行每日一次的短暂碰头会(比如说,15分钟)来讨论 工程的状态。图1描绘了这种Scrum过程。有关于Scrum的更多细节,请访问网站controlchaos.com。 ![](https://i-blog.csdnimg.cn/blog_migrate/5afe65b3e17a09c7ae5a5396daa61074.jpeg) 图1:Scrum敏捷过程简要描绘 敏 捷过程的一个普通主题就是迭代性开发。例如,尽管XP的工作就象Scrum一样工作,但是它使用了基于每周一次的迭代的季度发行的概念(如图2所示)。还 该特征are提供in该表单of用户故事,典型地是由客户使用一到三行语句来描述一下相应的特征。我在此对XP的解释可能过分简化;其实,关于XP还有其 它大量内容,例如结对编程(pair programming),共同讨论(sit together)与持续构建(continuous build)等。有关于XP的更多细节请访问网站extremeprogramming.org。 至 此,我们已经简单分析了解了两种敏捷过程:Scrum和XP。这些内容极有助于收集用户特征请求并有助于整个工程管理。然而,作为开发者,我们需要把这些 特征实现到应用程序中。因此,接下来,让我们了解一下敏捷建模技术,这可能有助于我们建立用户需求和编码之间的“桥接”。 ![](https://i-blog.csdnimg.cn/blog_migrate/41a3c5dd4f9ee3ea699a6b79ab2d92fb.jpeg) 图2:XP敏捷过程简要描绘 四、敏捷设计 根据来自thefreedictionary.com网站的定义,模型是“一种初步的作品,最终的产品将基于之进行制作……也用于测试或完善一个最终的产品。”因此,本文中我将使用“模型”一词来描述图表及其它人为绘制内容。 敏捷模型驱动开发 由Scott Ambler创建的敏捷模型驱动开发(AMDD)为进行有效的建模提供了指南。不是创建广泛的模型,AMDD推荐创建“足够好”的模型。我最喜欢的Scott的一句话就是“你的目标是构建一种共同的理解而不是编写一篇详细的文档。” AMDD建议使用两种类型的模型:需求(requirements)和架构(architecture)。需求模型有域模型(参考图3)、用法模型(例如用户故事/用例,参考图4)以及UI模型(例如原型和流程图,分别参考图5和图6)等。 ![](https://i-blog.csdnimg.cn/blog_migrate/3cffab09f114b908b79b921e4ac22254.jpeg) 图3:域模型 ![](https://i-blog.csdnimg.cn/blog_migrate/905410ee55c2e43700465937e90aea3a.jpeg) 图4:用法模型 图5:原型形式的UI模型 图6:流程图形式的UI模型 图7:架构模型中的自由形式(freeform)的模型 架构模型中可以包括一种自由形式的模型,如图7所示。 有关于AMDD并没有太多的资料可循,因为它仅为敏捷建模提供了最小的指南。有关于敏捷建模的更多细节,请访问网站agilemodeling.com。 敏捷绘图 在 继续下面的讨论前,请允许我简短地介绍一种新颖而相当简单的技术—敏捷绘图;我正是借助于它绘制了上面的图3~7。这一技术成为略显“笨重”的统一建模语 言(UML)的一种替代,但是也可以用于补充UML。敏捷绘图为建模提供了最小指南,同时增加了对基于图形设计概念设计这些模型的吸引力。敏捷绘图背后的 核心概念包括了四个基本组件(圆、矩形、线及文本),它们使敏捷绘图成为一种事实上可以自由标志的建模技术。通过这四种概念,你几乎能够手工(或借助于一 种绘图程序)绘制出任何模型。 更多的细节请访问网站agiledraw.org。 重构 敏 捷方法的一个核心内容就是,它不推荐一开始就进行过多的设计而使你能够尽快地向顾客展示实际软件的开发结果—这与编写全面细致的实际上没有人会读或维护的 文档的方法形成对照。当然,其缺点在于,它减少了程序开发过程中的设计量。然而,这也未必是一件糟糕的事情,因为对于大多数程序员来说,一旦他们开始编码 就会找到更好的解决问题的办法。 例如,在对问题进行第一遍加工之后,我们往往能够找到更为简洁的构建我们的代码的方法—或者是通过改进我们自己的设计或者是因为我们学到了一种更好的使用一种框架(例如Hibernate或Spring)的方法。 这种代码改进技术被称作“重构”,被认为是一种连续的设计活动。 重构并非无足轻重;如今它出现在许多的集成开发环境(例如Eclipse和IntelliJ IDEA)的菜单选项中。在此,我建议您访问Martin Fowler的网站—refactoring.com以更多地了解有关重构的信息;当然,其中还提供了大量的与重构相关的技术介绍。 其它设计考虑 尽 管重构能够有助于代码改进,但是,可能还有其它许多的内容需要你首先考虑;其中包括设计事务管理模式,异常处理,设计簇方案,还有应用程序安全(认证,授 权和加密)等。任何没有考虑这些重要因素的企业级工程很可能会在后期遇到各种麻烦。在XP工程开发中的一个普通问题就是,应该尽最大努力避免把大量的问题 留待后期去重构。即使是绘制如图7所示的极其简略的架构模型也能有助于解决在此所列出的诸多重要的设计问题。 五、敏捷Java开发 现在,既然我们已经讨论完敏捷过程与建模,那么接下来,让我们开始讨论编码的问题。然而,在正式开始编码前,搭建适当的开发环境是相当重要的。因此,在开始讨论Hibernate,Spring及其它技术前,让我们来首先分析一下搭建开发环境的问题。 建立环境—JDK、Ant、JUnit与版本控制 在正式进行开发Java应用程序之前,需要准备一些小工具,例如Java标准版开发包,一个构建工具(例如Apache Ant),一个重要的敏捷开发工具,一个单元测试框架(例如JUnit)等。 Apache Ant Ant 通常用于构建Java应用程序,然而,它并不仅仅是一个构建工具。例如,其它一些常见的Ant任务还包括javac,copy,delete,move, junit,cvs,ftp,mail,exec和sleep—所有这些功能都可分别用于从文件管理到代码编译再到发送电子邮件等各个方面。你甚至还能够 使用它来编写你自己的定制标签;另外,还存在大量可用的开源和商业Ant任务。 有关于Ant的更多细节,请访问网站ant.apache.org。 JUnit与测试驱动开发(TDD) Erich Gamma和Kent Beck最早实现了JUnit框架。这个框架中的JUnit类提供了许多断言方法(例如,assertTrue和assertNull),这些断言有助于 你测试期望结果。JUnit是一个简单而强有力的单元测试框架工具。当把它与测试驱动开发(TDD;testdriven.com,由Kent Beck创建的一种方法)相结合时,这个框架能够极大地帮助你编写更好、更清晰、更稳定的代码。据TDD建议,在你编写实际的代码之前要先编写相应的测试 代码—这是一种根本性的思想转变,但是我强烈推荐你对它作进一步的研究。 有关于JUnit的更多细节请访问网站junit.org。 版本控制、命名标准及其它 最后,为了使一个开发团队高效地开展工作,很有必要建立一个开发目录结构,确定类/文件命名约定定义,以及确定所使用的版本控制软件(例如CVS)—所有这些都是应该预以考虑的关键步骤。 六、基于Hibernate进行数据层开发 关 系数据库与面向对象技术已经出现一段时间了,而且看上去它们的未来也完全可以预测。假定在典型情况下Java开发者使用这两种技术进行工作,那么,他们经 常使用JDBC来编写数据存取对象(DAO)中的映射代码从而实现数据存取—典型情况下,数据的来回传递是借助于数据传输对象(DTO)实现的。作为使用 JDBC的另一种替代方法是使用EJB实体bean;然而,在EJB 3.0之前,这一直被认为是一种“笨拙”的方法—它们都是远程对象。那么,如果你想使用POJO通过一种敏捷方法来实现Java持久性存储,该怎么办呢? 答案是借助于例如Hibernate这样的一种ORM框架。 对象关系映射(ORM)代码消除了手工编写JDBC调用的需要,从而使你在XML文件中完成映射,然后简单地以POJO方式来操作数据库记录。Hibernate是一个流行的ORM框架,在Java开发社区中广泛使用。事实上,由于它的流行性,EJB 3.0规范的研发中非常紧密地参考了Hibernate模型。 Hibernate 支持大量关系数据库(通过它的dialect类)。为了使用这个框架,我们首先需要配置数据库连接—典型地,这是在一个称为 hibernate.cfg.xml的文件中实现的。然后,在典型情况下,针对使用的每一个表格,我们都把它们映射到一个相应的Java类。例如,下面一 行代码展示了一个针对一个名为Department的表格的映射(完整的代码位于Department.hbm.xml文件),它实现把这个表格映射到一 个名字也叫Department的Java类。
<class name="com.visualpatterns.timex.model.Department" table="Department"> | 下面这一行代码则展示了针对数据库表格中几个列的映射。其中,departmentCode是一个主键(以数据库术语),而用Hibernate/ORM术语来说则是一个唯一对象标识符: <id name="departmentCode" column="departmentCode"><property name="name" column="name"/> 一旦配置好数据库和映射关系,我们就可以简单地从一个SessionFactory中取得一个Hibernate会话(实质上是一个JDBC数据库连 接),并以一个Java对象方式来操作记录数据。下面的代码展示了这一点(该代码使用一个值为“IT”的departmentCode取回一个 Department记录):
Session session = sessionFactory.getCurrentSession();department = (Department) session.get(Department.class,"IT"); | 你可能已经猜出,Hibernate还提供方法用于保存和删除数据库记录(对象)。这其中的方法包括save、load、get、update、merge、saveOrUpdate和delete等。 Hibernate 的一个最强有力的特征之一是它的Hibernate查询语言(HQL)。这是一个类SQL语言而且功能十分强大,它支持例如连接、聚合函数、参数替代、表 达式和排序等许多功能。下面展示了一个极其简单的示例—说明如何从Department表格中提取一个对象列表:
departmentList =session.createQuery("from Department ORDER BY name").list(); | 然而,我们在此仅触及到一些皮毛,因为Hibernate还提供了其它许多特征,例如记录锁定、关联、本地查询、存储过程支持、拦截器和过滤器,等等。 有关Hibernate的更多细节,请访问网站hibernate.org。 七、基于Spring框架进行Web层开发 Spring(springframework.org)是一个无法用一句话来描述的非常复杂的框架。例如,它支持IoC(控制反转)(martinfowler.com/articles/injection.html),一个完整的Web MVC框架,JDBC,ORM,JEE/Web服务,面向方面编程(AOP),声明性事务管理,作业调度,邮件,等等。 基于Spring框架进行开发具有若干优点,例如更为容易和更整洁的单元测试,能够结合企业服务(例如声明性事务管理)在轻量级容器(如Apache Tomcat)内使用POJO,方便的数据存取,以及通过ORM和JDBC集成实现一致的数据异常处理,在一个Web/应用程序服务器上实现作业调度,等。 Spring Web MVC框架 Spring Web MVC框架是一个强壮、灵活、设计良好的框架,用于基于MVC设计模式实现Web应用程序的快速开发。使用Spring模块的一个非常关键的优点就是,它 能够直接绑定到业务对象—不象其它框架需要你继承特定的子类。下面,让我们来回顾这个框架中的一些与Java及其配置相关的概念。 Spring MVC Java概念 Spring MVC中提供了如下关键的Java概念: ◆控制器 ◆模型和视图对象 ◆命令(表单支持)对象 ◆校验器对象 ◆标签库 Spring MVC的一个非常优秀的特征是,它提供了大量可供选用的控制器类(见图8)。当然,如果你刚开始学习这个框架的话,这可能不是一件好事情,因为你可能难以 决定使用哪种控制器类。例如,我习惯于在操作HTML表单时使用SimpleFormController,而当我不需要使用控制器时仅使用 UrlFilenameViewController。有些情况下,当我想使用一种非表单式控制器时,我只是简单地实现控制器接口。 ![](https://i-blog.csdnimg.cn/blog_migrate/cfc98f4b07501022d0231787acbd7279.jpeg) 图8:Spring MVC提供了大量可供选用的控制器类 许 多关键的与GET和POST相关的Spring控制器方法都会返回一个ModelAndView对象—它可以包含与模型相关的数据和一个视图的名字(或对 一个视图对象的引用)。对于支持HTML表单的控制器类来说,我们可以使用可选的命令和校验器对象来把HTML表单域绑定到Java对象并且对输入数据进 行校验。至于视图本身,Spring支持多种视图技术,包括JSP,Velocity,还有JasperReports。下面让我们来分析如何在视图中使 用JSP。 前面的图5展示了一个示例表单的屏幕快照,它可以在JSP中并结 合Spring的绑定标签库进行开发。这种Spring绑定标签库相当简单但是功能强大。典型情况下,它被应用于JSP文件中—经由< spring:bind>标签—它实质上实现把HTML表单域绑定到命令对象。而且,它还提供到JSP中特定变量的存取;另外,使用 JavaServer页面标准标签库(JSTL)表达式例如${status.value}也可以对这种变量进行存取。下面的代码片断展示了 spring:bind标签库的工作方式。请注意在此我们是如何直接绑定到Department域(业务)对象的(在Hibernate一节我们已经讨论 过):
<spring:bind path="command.departmentCode"><input name='<c:out value="${status.expression}"/>'type="text" size="10" maxlength="30"></spring:bind> | 除了spring:bind之外,Spring 2.0中还引入一些新的标签库,从而使得操作单个HTML表单元素更为容易。这其中的一些新标签包括form:input,form:textarea,等等。 Spring MVC配置概念 到 现在为止,我们仅分析了Spring MVC中的一些与Java相关的概念。当然Spring还有其它许多方面需要进行配置。在系统一开始运行时,必须在Web服务器的Web.xml文件中配 置它的DispatcherServlet类;这样以来,匹配某一种特定扩展(如.htm)的文件就可以由Spring MVC进行处理。一旦配置好这一点,一切就会转入到Spring MVC控制之中。此后,我们还要在一个Spring应用程序上下文文件内配置视图解析器和处理器映射。视图解析器负责把到来的URL映射为实际的视图名 称,而处理器映射部分则负责把到来的URL映射为控制器类。 Spring ORM Spring 的一大优点是它对于第三方API(例如JDBC,JAX-RPC,Hibernate,等等)的支持。例如,如果我们结合Hibernate使用 Spring的话,我们不需要自己去编码实现管理Hibernate的sessionFactory、会话及可编程事务管理。结合Hibernate使用 Spring的优点在于,它能够把与Hibernate相关的编程量减少几乎一半;同时,还提供其它的优点,例如更容易的测试,一致的异常层次以及对 Hibernate资源的管理等。 有关更多细节,请访问网站springframework.org。 八、基于Eclipse IDE进行高效的Java开发 Eclipse 平台实质上是一个框架,它提供了一组服务,其它插件能够基于其上运行。每种插件都是基于相同的平台开发,进而组成一组高度集成的工具。当前, Eclipse网站拥有许多正在开发中的子工程,包括从对各种编程语言的支持到建模插件到报告,测试,性能等,几乎涉及到软件开发过程的方方面面。 Eclipse的核心概念中包括了一个工作区—实质上是一个相应于你的工程的目录。Eclipse中最主要的屏幕称作工作台(见图9)。该工作台中包含了一组编辑器和视图。 ![](https://i-blog.csdnimg.cn/blog_migrate/ed475d0762b5fc9d4479de583eb8bbe9.jpeg) 图9:Eclipse中最主要的工作台屏幕 其中,一个核心Eclipse插件就是Java开发工具(JDT)。这是一个极其强壮的插件,支持很多的Java开发内容,例如管理与Java相关的文 件(.java,.class和.jar),Java视图,编译,代码格式化,调试,重构及语法加亮等—事实上,这个JDT插件本身就是一个十分成熟的产 品。 另 一个重要的插件是Eclipse Web工具平台(WTP),用于开发J2EE Web应用程序。它提供了许多编辑器,如JSP,HTML,CSS,JavaScript和WSDL。另外,它还提供了极其方便的数据库查询和建模工具以 用于管理数据库、运行查询和分析数据。当然,这个插件还有一个主要的特征是能够容易地创建和测试Web服务。 除 了在Eclipse.org网站提供的插件外,在网上还存在其它不少的可用于Eclipse的插件。一些网站,例如 eclipseplugincentral.com,eclipse-plugins.2y.net和myeclipseide.com都提供了大量的 Eclipse插件。 其它Eclipse特征包括通过与CVS紧密集成、支持团队开发、、强壮的帮助系统、大量的定制功能及好用的快捷键等。简言之,Eclipse提供了能够在应用程序的各个层(即数据层,Web层和业务层)上进行开发的支持工具。 九、高级话题 如 果我们生活在一个完美的世界中,那么,我们只需简单地收集用户要求,对之进行编码,然后把一个完美稳定运行的应用程序提交给用户即万事大吉。然而,作为开 发者,我们知道这根本不可能,总存在这样或那样的问题需要解决—例如,在很多情况下需要我们监视应用程序的运行状况。为此,在本节中,让我们来共同回顾一 下与此相关的一些辅助技术。 调试 调 试是定位和修改错误的一种典型过程,尽管它还能够用于单步式代码调试以确保相应的逻辑正确工作。Eclipse的JDT插件提供了一个强有力的Java调 试器,它支持我们调试运行于本地或远程Java服务器上的Java程序。就象大多数调试器一样,这个Eclipse JDT调试器能够单步调试代码(每次执行一行代码或跳转到一个特定的断点)和变量检查。另外,它还提供一种称作“Hotswap”的强有力的特征;基于这 一特征,我们可以实现在同一个会话内自由地修改代码,重新编译并继续调试。由于按照你自己的意图建立一个调试会话往往需要耗费不少的时间,所以,这种特征 为我们提供了方便。图10展示了我们调试Java代码的方式;在这种环境下,既能够看到数据库中的数据,也能在同时看到控制台的输出内容—所有这一切都通 过两个完全不同的插件(JDT和WTP)高度集成到一起。 ![](https://i-blog.csdnimg.cn/blog_migrate/76a549b6478ce13e25b2f347a5846ee2.jpeg) 图10:基于Eclipse JDT调试器进行代码调试 外围配置(Profiling) 可 以说,只要使用Java进行开发,几乎一定会用到Java外围配置程序。在Java程序的开发过程中,它们能够帮助我们分析堆栈以了解内存用法、漏洞情 况、CPU利用率、跟踪对象和方法,从而有助于我们最终决定影响系统性能的瓶颈之所在。如今,有很多现成的开源配置程序可用,也有一些商业工具(如 YourKit Java Profiler和Quest公司开发的JProbe Suite)。其中,一些配置程序以独立的Java程序方式运行,而另一些则可能会被发布到一个servlet容器上,还有一些则以Eclipse插件形 式存在。因此,如果你正在寻找一种开源形式的配置程序的话,你可以转到网址www.manageability.org/blog/stuff/open -source-profilers-for-java/view/处,这里列出了许多供你使用的配置工具。 然而,被许多人称为是最优秀的配置程序之一的NetBeans Profiler非常值得你尝试一下。不过,我也没有用过,但是仅从其相应的屏幕快照看去就感觉到相当诱人。要深入学习之,请访问网址profiler.netbeans.org。 日志 日志也是软件开发的一个重要方面—日志记录方式可以是简单的打印语句甚至是复杂的基于数据库的日志。日志类型包括审计日志、跟踪日志以及错误报告日志,等等。 在Java 世界中,通常使用两个日志框架—Apache Log4J(logging.apache.org/log4j/)和JDK Logging(java.sun.com)。另一种选择是使用Apache的Jakarta Commons Logging(jakarta.apache.org),它能够负责建立各种日志框架(包括Log4J和JDKLogging)之间的一种“瘦型”桥 接。尽管我们能够使用简单的打印语句从你的程序中输出消息,但是,日志框架有助于我们基于不同的目的地(文件,数据库,远程)、级别(致命错误,普通错 误,警告)和格式(日期和时间)控制消息的输出。另外,日志框架还能够提供其它一些优点—例如,当日志文件达到一定长度时实现自动地删除过时的日志内容。 监视 Java 平台标准版(JAVA SE)5.0提供了内置的远程监视,管理和基于JConsole Swing的工具(见图11),为运行于JAVA SE 5.0+平台的应用程序提供了监视功能。我们可以利用这些工具来观察Java应用程序的资源利用情况。例如,它能够帮助检测内存问题,类加载,垃圾回收, 控制JDK日志级别,以及管理一个应用程序的托管Bean(MBean)。而且,Spring的JMX支持我们自动地注册POJO,这为我们提供了一种强 有力的支持,因为我们可以很容易地编写出能够被监视的业务类型对象。例如,在我们的示例应用程序中,这可以包括取回的时间表中的记录个数和登录个数。 ![](https://i-blog.csdnimg.cn/blog_migrate/62c91018e2ec339ec4af3d5b7d72073e.jpeg) 图11:JAVA SE 5.0所提供的远程监视和管理工具 十、结论 在本文中,我介绍了大量的基本内容—本文仅作为基于Spring,Hibernate和Eclipse框架进行敏捷Java开发的一个指南。为了全面理解本文中相关内容,我还提供了一个具有完整功能的示例—时间表应用程序。 最后,我非常希望本文能够为读者进行敏捷式Java开发助一臂之力。 |