BEA WebLogic Portal 8.1的发布引入了大量新技术。其中包括:包含注释的Java页面流、Java控件以及用来支持它的新IDE。程序包中也包含有在线教程,用于演示如何才能最有效地利用这些新技术。
我们使用BEA WebLogic Workshop、Java页面流和Java控件创建了一个大型门户应用程序,它由大约200个包含五个不同功能区域的页面组成。在开始之前,我们对这项技术进行一下评估。我们旨在创建一种架构,以便使得我们能够基于以下软件工程原理进行测试驱动开发:
松散耦合
每一层具有清晰职责的分层架构
通过简单的小型类而实现的可维护代码
可单元测试的代码
持续集成
BEA参考文档并未明确介绍如何在BEA Portal应用程序中实现这些特征。这就意味着我们必须找到一种方式将从传统软件工程所获得的这些优点并入新的BEA技术中。在本文中,我们将通过Java页面流和Java控件架构来讨论实现这些优点的方式。
扩展后的页面流架构
在架构中各组件之间创建松散耦合的主要原因是为了确保在引入更改时,除要更改的组件自身外,尽可能不对其他组件造成影响。图1展示了基本的Java页面流架构。
图1 基本的分层架构
从图1中可看出,此架构使用了清晰的分层方法。然而,除了最简单的项目,此基础架构对所有项目来说都太简单了。典型的Web应用程序用例由三个主要部分组成:
准备一个包含一些预先填充的数据和一个表单的界面,并将其呈现给用户
用户将数据输入表单中
数据经认证并发送回后端系统
通常必须添加负责将数据从后端系统转换为可呈现表单的附加代码,以执行复杂的认证并将数据转换回后端系统的格式。这意味着要在应用程序中引入一个新层。我们选择将此层称为Action Delegate(动作委托)层(参见图2)。
图2 扩展后的分层架构
Action Delegate层负责编排应用程序的逻辑。这意味着我们将编排工作从页面流控制器(Page Flow Controller,PFC)中的单个动作方法委托给ActionDelegate类中的对应方法。我们的经验是:在正常情况下,对每个PFC使用一个ActionDelegate类是一种比较好的做法。这为我们提供了良好的责任分割。PFC的动作方法现在成了外观。它们唯一的用途是将其工作委托给ActionDelegate,并基于ActionDelegate的返回值跳转到适当的jsp/嵌套页面流。
如果PFC有许多动作方法,则ActionDelegate层让我们有可能使用来自一个PFC的多个ActionDelegate以对逻辑连接起来的功能进行分组,并保持小型且可维护的ActionDelegate类。此处要注意的一点是,如果发现PFC中有大量的动作方法,则可以考虑将其重构为一个或多个嵌套页面流。
另一种缩小PFC的方式是放弃使用用于创建表单bean的内置功能。由Wrokshop Wizard所创建的表单bean被实现为对应PFC中的��态内部类。此外,完全可以创建自己的表单Bean并使用它们。这样会由于使用了较少的代码复制而得到更清晰的代码。
可测试代码
Java控件的概念非常重要。它允许通过对常规Java方法的调用来轻松访问不同的后端技术。然而存在的一些限制使得它们无法达到应有的灵活性。在BEA WebLogic容器外不能对Java控件进行实例化。这同样适用于PFC。仅可在三个地方对Java控件进行实例化——PFC、Workflow中,或者另一个Java控件中。当对Java控件和PFC创建JUnit测试时,这就造成了挑战——测试必须在容器内部运行。这与尽可能缩短开发-编译-测试周期的原则相冲突。
然而,这也具有一个优点:必须在PFC中实例化Java控件的要求将Java控件的依赖注入强制实施到我们的ActionDelegate中。我们可以很容易地向Java控件添加业务接口。我们正是通过将此接口用作ActionDelegate的参数来实施依赖注入的。这带给我们ActionDelegate层的另一个优点:在常规JUnit测试用例中,有可能在容器外部测试PFC的实际功能。要记得,PFC动作方法现在仅用作外观——实际工作在对应的ActionDelegate方法中进行。当为PFC动作方法创建JUnit测试时,通常需要做的是:
创建此方法正使用的任何Java控件的模仿版本
在HttpServletRequest和HttpSession模仿对象中设置正确值
实例化ActionDelegate类,并调用具有模仿对象的实际方法
在请求、会话或其他地方断言方法的返回值或修改后数据中的更改。
松散耦合
如上所述,在架构中的组件之间创建松散耦合的主要原因之一是为了确保在引入更改时,除要更改的组件自身外,尽可能不对其他组件造成影响。这转化为用另一个组件来取代整个组件的能力。这对集成层组件尤其有用。这使得有可能在面向现实后端系统的现实集成层组件之间进行轻松切换,例如在一个具有面向后端系统模拟器的组件的集成层中。如果正在进行面向开发中的后端系统层的开发,则在活动组件与模拟器组件之间进行轻松切换的能力就非常重要。
实现这种类型的组件间松散耦合的一种方式是使用反向控制(inversion of control,IoC)框架,比如Spring,它包含有自己的bean容器。Spring允许通过XML配置文件来配置要创建哪一组件。让我们回到后端模拟器的例子:如果意欲在面向现实后端系统的集成组件与面向后端系统模拟器的集成组件之间进行切换,则只需在XML文件中更改集成组件的调用方入口。
遗憾的是,很难获得常规的Java控件来用于此架构中。其原因在于Java控件要遵守以下规则,即它不能够在PFC、Workflow或另一个Java控件之外被创建。不能使用Spring IoC容器来实例化Java控件。
好在BEA已创建了一个开源项目,该项目进一步发展了Java控件的概念。该项目被称为Beehive(参看“参考资料”部分的第一条),除了BEA的原始Java控件之外,Beehive Java控件还具有另一个实现模型。Beehive Java控件是常规的POJO,因此能够用Spring Bean容器进行实例化。由于BEA WebLogic Server 9也使用POJO Java控件实现模型,所以对于此版本,Spring集成将大大简化。在BEA WebLogic Server 9中,Spring实际变成了一等公民,从而有可能从WebLogic控制台或通过JMX来监控Spring bean(参看“参考资料”部分的第二条)。
代码质量及持续集成
为了在重构、语法和语义检查以及代码生成方面获得IDE帮助,除WebLogic Workshop之外,我们还使用Eclipse。我们使用适用于门户、JSP、页面流和Java控件开发的Workshop。在Eclipse中,我们将编写具有帮助器类、JUnit测试和模仿对象的ActonDelegate。由于Eclipse对重构、代码检查和代码生成具有较好的支持,因为对于我们来说是一个很自然的选择。为了获得尽可能接近我们的编码标准的代码,我们将编码标准配置到Eclipse代码分析器中,从而获得对潜在的不良代码的实时反馈。使用两个IDE存在一些开销,但我们认为是值得的。
BEA也看到了Eclipse的优点,所以Workshop的下一版本,即Workshop Studio 3.0,附带有Eclipse插件。此后将有可能在一个工具中执行整个开发过程,从而利用二者的优点。
为了获得对代码状态的更为自动化的反馈,当谈到进行JUnit测试以及代码质量和代码聚合等各方面时,我们使用Maven和CruiseControl来实现持续集成。由于BEA WebLogic Workshop提供了用于构建门户应用程序的Ant任务,因此很容易将其整合到Maven编译过程中。我们设定以下目标,首先编译我们的“非workshop”模块,接着根据其功能将其复制到APP-INF/lib或WEB-INF/lib中,最后使用workshop中的Ant任务编译整个门户应用程序。项目的目录结构基于TSSS 2004上Vincent Massol所提出的“Enterprise builds”(参见“参考资料”部分第三条)。这是一个合理且实用的结构,并且运行得非常好。
结束语
当引入新技术时,通常要随之产生一系列新的开发实践。我们意欲忘记已作为所有专业软件开发基础的基本技能和现有的最佳实践。通过将注意力集中在测试驱动开发的合理软件工程原理上,我们就能够使用大量新技术开发大型BEA WebLogic Portal应用程序,从而实现通过持续集成开发高质量代码的松散耦合架构。