COTS应用程序框架简介
J2EE以其成熟的架构、优秀的跨平台特性和稳定的性能表现等正逐渐成为企业应用的首选技术体系。但是由于多种因素,开发J2EE程序是一个相对较复杂的过程,很多基于J2EE的项目最终都以失败而告终,但这并不能归咎于J2EE本身,而是由于在项目的实现中对J2EE的不恰当运用所造成的。
为解决这个问题,除了功能更强大的IDE工具支持外,一个优秀的应用程序框架的存在也是不可或缺的。这个框架必须提供良好的架构,使得应用程序的结构清晰,从而保证应用程序具有良好的可扩展性、可维护性和性能等;换句话说,框架的架构在一定程序上决定了应用程序的架构,而应用程序的架构基本上决定了其本身各方面的质量,因此框架的好坏程度也就决定了应用程序的好坏程度。
很多类似的产品(或者项目),例如struts,turbine,spring等等,都是在这种背景和需求下产生的,关于这些框架的详细信息可到其各自的网站上浏览。
本文将要阐述的是一个简单易用而又功能强大的J2EE应用程序框架“COTS应用程序框架”。简单的说,COTS框架:
l 实现了充分优化的应用程序架构,保证应用程序的可靠性、可维护性、可扩展性和优异的性能;
l 充分利用面向对象的思想和方法,保证应用程序开发的简洁性、快速性和高效性;
l 提供了一些实用工具辅助应用程序开发;
l 提供了对应用程序进行部署和安装的支持。
在后面的介绍中,我们将从这几个方面入手,剖析COTS应用程序框架,并分析了多个COTS应用程序之间以及COTS应用程序和非COST应用程序之间的交互问题。
本文假设阅读者具有相当的J2EE和MVC的知识背景,在文中的一些术语,将不做详细解释。本文针对对象是对J2EE应用程序框架技术感兴趣以及正在寻找一种合适的框架来替代现有相对使用复杂的开发框架的JAVA技术人员和项目管理人员。
本文目的,通过阅读本文,读者将会对COTS框架本身以及COTS所使用的技术有一个大体的了解。本文是入门级读物,如果读者具有相关的技术只是背景,本文亦是很好的技术讨论文章。
COTS架构
一般来讲,企业应用系统都具有高度的复杂性,并要求对业务变化能快速反应。从系统论的观点和计算机科学理论与实践来讲,用“层次”的观点来分析并构建企业应用是一种非常适用的方法,而且这也是很多企业和计算机系统所应用的方法。下图是一个企业应用的典型分层结构:
客户端为应用系统与客户进行交互的图形界面,对于基于B/S结构的应用来说,这个客户端一般就是一个WEB浏览器;客户端与视图逻辑通过一个标准的协议进行通信,例如HTTP协议,而视图逻辑则是负责将业务逻辑处理完的数据转换成与客户端通信协议所需要的格式;业务逻辑则是执行应用系统的逻辑,是一个应用系统的核心,它可能要通过数据访问层与数据存储层进行数据交互。
对于多数企业应用的开发来说,焦点主要集中在视图逻辑和业务逻辑上,数据访问一般是一组标准的组件,绝大多数情况都不成为应用开发的重点;数据存储的形式一般有数据库管理系统、文件系统或者其他相关系统,一般的是一个定义的过程,占整个应用开发工作量的很少一部分。因此视图逻辑和业务逻辑的开发及运行对应用系统在整个生命周期中的各过程和质量指标的影响将变得更加突出。
从上图中我们可以看出视图逻辑直接发出业务逻辑调用请求,使得他们之间耦合程度比较高;关键子系统之间的高耦合性必然造成应用系统在开发和运行期间的多种问题,例如,视图逻辑和业务逻辑之间的并行开发程度,应用系统的可维护性,适应性等。MVC模式在很大程度上解决了这些问题。
从上图中我们可以看到视图逻辑和业务逻辑之间没有直接关联,而是通过控制器发生间接的联系,这种联系使得他们之间的耦合程度非常非常的低,保证了应用程序开发、运行和维护的很大便利性和快捷性。
COTS应用程序框架是一个完整的MVC实现。控制器在接受到用户请求后,根据请求–模型映射表动态地调用业务逻辑,这里“动态”的含义是指根据当前用户的不同或者请求中某项数据的不同而调用不同的业务逻辑来处理;在业务处理完成后,控制器再根据请求–视图映射调用一个视图将模型处理完的数据展现到客户端。在COTS框架中,控制器是核心,它维护请求–模型映射表和请求–视图映射表,并使视图和模型相互独立。
模型在COTS系统中又被称为业务组件(Business Logic Component,BLC),一个业务组件是一个独立的Java类,其中包含一个或多个业务逻辑方法。
在COTS框架中视图由JSP承担,JSP不直接调用业务逻辑方法,也就是说每个JSP只进行必要的数据格式转换然后将这些数据显示到客户端(以HTML形式写到客户端浏览器中)。
COTS的逻辑结构图如下:
COTS框架从功能上可以分成下面几个子系统:
控制器子系统:主要功能是接受用户请求,然后调用若干个相应的业务组件中的方法(业务逻辑方法),最后调用一个视图展现最终结果给客户。
业务组件子系统;业务组件子系统提供了两个业务组件基类(AbstractBLC,DBBLC),所有其他的业务组件都必须直接或间接的从这两个基类继承;同时该子系统还提供了业务组件的缓存,业务逻辑方法的远程调用等服务。
视图子系统;视图子系统包含了所有的用户界面逻辑,用来向用户展现业务逻辑处理完的数据。视图中不包含任何形式的业务逻辑调用。
数据传输对象子系统;在COTS框架中,数据的传输通路有下面三种:视图和控制器之间,控制器和业务组件之间,业务组件和基础组件之间;前面两个通路必须以数据传输对象(BizData)来传输数据,后面的通路则不一定通过数据传输对象的形式来传输。数据传输对象使得数据以统一的方式在通路上被传输,并被控制器、业务组件,视图或者基础组件访问,同时还提供了数据加密、解密和产生摘要等附加功能。
基础组件子系统:为业务组件提供一些业务无关的服务,例如数据存取,SMTP客户端,POP3客户端等等,这些组件由框架提供,可以被业务组件任意调用。
COTS的控制器
控制器是COTS的核心,在接收到一个用户的请求后,它首先解析所有的请求数据并验证这些数据,验证通过后这些数据被添加到一个数据传输对象中。在COTS系统中数据验证分为两种:一种是字段验证,即对一个字段的类型、是否可空、最大值和最小值等进行验证;另外一种是组合条件验证,这个组合条件是一个逻辑表达式,如果这个表达式的值为false,则验证不通过。客户请求数据成功处理完毕之后,控制器将调用匹配的业务逻辑方法,最后调用一个视图逻辑(JSP)向用户展现处理结果。
此外,控制器还负责客户的权限验证,即判断一个用户是否有权限发出一个请求,如果当前客户对其所发出的请求没有权限,则控制器将不处理这个请求,而是直接发送一个错误信息到客户端。
控制器维护两个映射表:请求–模型映射和请求–视图映射,前面的映射决定执行哪些业务逻辑方法来响应一个用户请求,后面的映射决定在业务逻辑方法执行完毕后,执行哪一个视图逻辑来向用户展示最终结果。两个映射被保存在一个xml文件中,该文件的一个实例如下:
<?xml version="1.0" encoding="GB2312"?>
<requests>
<request>
<name>modifyMyPassword</name>
<validate>
<field name=”” requires=”” type=”” minValue=”” maxValue=””/>
<on cond=”” message=””/>
</validate>
<model name="com.dream.app.sys.User.modifyMyPassword" on="" asyn=”true|false” />
<dispatch url="SysHome.jsp" type="redirect" on="" default="true"/>
</request>
</requests>
其中的on属性为一个逻辑运算表达式,如果指定了该属性,则只有当该表达式的值为真时才执行这个模型或视图。用户请求配置将会在《用户请求配置指南》中详细说明。
控制器的处理逻辑如下图所示。
COTS的业务组件
一个业务组件(Business Logic Component, BLC)是一个独立的java类,该类从特定的类(AbstractBLC或者DBBLC)继承,并包含一个或多个业务逻辑方法(Business Logic, BL方法),每个方法完成一个独立的业务逻辑,这些BL方法具有两种接口形式:
int BL方法名(BizData requestData);对于不需要用户的Session信息的BL方法可以按照这种形式申明;requestData为客户在请求这个BL方法时的请求数据。
int BL方法名(BizData requestData,BizData sessionData);对于需要用户Session信息的BL方法可以按照这种形式申明;这里的sessionData为当前用户的session数据(具体数据的内容)每个application可以自由定义。
一个业务逻辑组件可以从两个类中的一个继承,一是AbstractBLC,所有的BLC都直接或间接从该类继承,AbstractBLC只提供一个业务组件所必须的最基本的支持;也可以从DBBLC继承,典型情况下,一个从DBBLC派生的子类与一个数据库表相对应,DBBLC提供了访问单表的大多数方法,因此当从DBBLC派生一个新类时(需要指定与该DBBLC相称对应的数据库表名),那么该子类就自动拥有了对该表进行增加、删除、查询和修改等操作,可继承的数据库操作方法见DBBLC的申明。
一个BL方法可以被客户端调用(通过控制器代理),也可以被另外一个BL方法直接调用(调用方式主要有:多个本地BLContext之间的交互;多个远程BLContext之间的交互;多个本地和远程BLContext之间的交互;不同BLContext中的业务方法交互)。
业务逻辑组件之间可以有继承的关系。
业务组件子系统的类图如下:
COTS的视图组件
COTS应用程序框架目前只支持JSP作为应用程序的视图逻辑来向用户展现一个请求的最终处理结果。
JSP不能直接发出业务逻辑请求,而只能单纯的从数据传输对象中取出相关数据并转换成用户需要的格式进行展现;而且JSP不清楚这个数据传输对象是由哪个业务逻辑处理的。
COTS的数据传输对象
在COTS框架中,数据的传输(客户端与控制器之间,控制器和业务逻辑方法,控制器和视图逻辑之间)通过一个统一的对象(BizData)进行。数据传输对象中的数据共有四类:单值数据、数组数据、记录数据和属性数据,属性数据不独立存在,附加于前三种类型数据。客户端数据通过名称–值成对传递给控制器,典型情况下是通过web form的提交来传递。
客户端数据的命名需要遵从COTS系统的FPath规范:一个FPath是一个数据元素的名称,通过该名称可以使客户端数据被系统自动识别和处理。FPath规范简要说明如下:
在FPath中@、/、[和]为特殊字符,用于区别FPath的不同部分,FPath的组成部分根据其类型不同而不同。FPath分为四类;
l 单值元素:name,name中不能包含特殊字符;
l 数组元素: 一维数组name[i],二维数组name[i][j],其中i、j为不包含/、@、[和]的字符串,推荐使用非负整数。
l 记录元素:table/field(=table/field[0]),table/field[i],table为记录所属于的表的名称,不能包含任何一个特殊字符。Filed为记录的字段的名称,也不能包含特殊字符;
l 属性元素:属性元素附加于上述三种元素,不独立存在。例如:name@attritbuteName,table/field@attributeName,table/field[i]@attributeName, table[i]/attrName。
数据对象还提供了数据加密、解密和摘要等功能,相应的算法由JDK提供。
关于FPath和数据对象的使用,将会在《FPath和数据对象使用指南》中详细说明。
COTS的基础组件
COTS框架还提供了功能强大的数据访问组件(Data Access Object,DAO,注意这里的DAO与一般的DAO模式有比较大的不同,一般的DAO模式是对某个或某几个表的增删改查,这里的DAO是对任意一个表进行增删改查,具有更大的适用性),该组件利用一个统一的数据字典完成数据传输对象中的记录型数据与数据库表中记录的映射,极大的简化了数据库访问操作,一般情况下不需要写SQL语句。DAO提供了对不同类型的数据库系统的支持,并且对部分系统的SQL实现中的函数进行抽象,例如SQL Server中求字符串的长度的函数为len,而oracle中为length,因此为sql server写的包含len函数的sql语句将不能在oracle中执行;如果用DAO组件来访问数据库,那么只需指定对某个字段进行len操作就可以了,DAO在数据访问时,会根据所要访问数据库的实际类型(需要在系统的配置文件中进行设置)进行相应的转换,即当数据库是一个oralce实例时,它会自动的将len转换成length。这样可以最大限度的保证应用程序可以自由的在不同数据库系统上进行移植。系统中可以配置多个DAO实例,每个实例负责对一个数据库进行访问,这些数据库可以是不同厂商的、不同类型的数据库系统;也就是说在业务逻辑组件(BLC)中,一个业务逻辑(BL)可以同时访问多个数据库系统。DAO的类图如下:
DAO支持分布式事务处理,在一个业务方法中要进行一个分布式的事务处理可按照如下的方式进行:
……
BizData d1 = new BizData();
BizData d2= new BizData();
……
DAO dao1 = context.getDAO(“dao1”);
DAO dao2 = context.getDAO(“dao2”);
TX tx = context.newTX();
Tx.begin()
Try{
dao1.delete(d1);
dao2.insert(d2);
tx.commit();
}catch(SQLException e){
tx.rollback();
}
…….
其中,dao1和dao2分别对两个数据库进行操作,要求在这两个数据库中分别进行的删除操作和增加操作以一个事务的方式进行。
数据访问的另一个特色是基于角色的完备的数据权限控制方案,这个方案可以控制任意一个角色在访问一个数据库表(或视图)时的行集和列集,并且对一个用户来说,他所拥有的数据权限是其对应的所有角色的数据权限的并集。
COTS框架还提供了SMTP客户端,POP3客户端和工作流引擎等其他组件,详细信息请参考开发指南。