应用系统架构(SSH架构)与AndroMDA基本原则
翻译者:Jason S.H.Chen
(英文地址:
http://www.andromda.org/index.php?option=com_content&view=article&id=108:application-architecture&catid=42:getting-started-java&Itemid=89)
应用架构:
现在工业界流行分层的企业应用系统架构。每层的组件分别完成不同的功能,各层的组件相互连接构成系统。各层之间像堆栈那样组织,位于上层的组件调用下层的组件。位于某层的组件通常可以调用同层或下层的组件。下面的图可以直观的显示现在工业界流行的企业应用分层架构。
表现层:表现层主要包括应用系统的UI组件。比如网页组件,富客户表单和用户交互处理组件等。
业务层:业务层主要封装应用系统的核心业务功能。简单的业务功能可以使用无状态的组件实现,而复杂的(long-running transactions),长事务处理可以使用有状态的工作流组件来实现。业务组件通常会采用面向服务的架构实现。组件提供业务接口,业务接口隐藏复杂的业务逻辑实现。
数据访问层:数据访问层提供访问和操作数据的API.此层的组件专注于底层数据的操作,而业务层的组件专注于业务逻辑的处理。此层的每个组件主要提供对某个业务实体的新增,读取,更新和删除操作。
数据存储:企业级应用需要将系统的数据保存于一种或多种数据存储中。数据库和文件系统是2种最常见的数据存储方式。
特别说明:上面所描述的层只是从逻辑功能上将组成应用系统的组件进行分组划分。而这些层在实际的物理服务器的部署情况可能会大相径庭。最简单的部署情况:所有层都部署在同一台物理服务器。稍复杂一点的情况:表现层部署在一台物理服务器上,业务层和数据访问层部署在一台物理服务器上,数据库部署在另外一台物理服务器上。在复杂一点的话,比如对于高并发性和高吞吐量的网站应用,可能需要使用数十台物理服务器对表现层做集群部署。
AndroMDA能生成的应用系统的架构:
现在我们明白了现在工业界流程的企业应用的基本思想,那让我们继续讨论AndroMDA是怎样实现这些思想的。AndroMDA通过输入使用UML描述的业务模型产生构成应用系统的各层组件。AndroMDA能够自动的将高层次的业务规格转换成对应的程序代码从而达到节约编写代码的时间。下面的图直观的描述了AndroMDA在J2EE应用系统各层所支持的JAVA技术。
表现层:对于构建基于web的应用系统,AndroMDA目前支持Struts和JSF两种技术。采用UML的活动图来描述页面流转,产生遵循Struts和JSF技术框架的web组件。
业务层:AndroMDA产生的业务层是由主要业务组件组成。他们可以采用Spring框架,此时需要在AndroMDA产生的空白方法中实现业务逻辑。也可以采用EJB框架,此时服务组件必须部署在EJB容器中(比如JBoss)。服务组件还可以封装成Web Service,以便不同技术平台的客户端访问。AndroMDA甚至可以产生业务流程,基于jBPM的工作流引擎(JBoss产品线的一部分)。
数据访问层:AndroMDA可利用当前最流行的对象关系映射工具Hibernate为应用系统的数据访问层产生组件。AndroMDA通过为UML模型中的实体生成数据访问对象来达到这个目的。这些数据访问对象通过调用Hibernate的API来完成数据库记录和实体对象之间的相互转换。AndroMDA也支持EJB,Seam等数据映射技术。
数据存储:因为AndroMDA产生的应用系统使用Hibernate访问数据库的数据,所以你可以选择任何Hibernate支持的数据库产品作为你的数据存储。
数据传递:
对于前面我们所讨论的的概念和思想,我们在此做些进一步的探讨。搞清楚应用系统各层之间的数据是怎样传递的是非常重要的。
回到上面的图,从下往上。如你所见,关系数据库将数据以记录的方式存储在数据表中。数据访问层的组件从数据库获取这些记录,并将记录转换为业务领域对应的实体对象。因此,这些对象又被称为业务实体。再到上一层,数据访问层将实体对象传给业务层(这里执行业务逻辑的处理)。最后要讨论的是业务层和表现层之间的数据传递方式,业界有2种流派。一派主张表采用现层直接访问业务实体的方式,另外一派主张则反对这样。他们主张将业务实体和表现层脱离开,业务层将表现层需要的信息打包成VO(value object)并传递到表现层。下面我们将详细比较下这两种数据传递方式。
第一种传递方式只有实体对象,没有VO;实现简单。你不需要创建VO和编写任何实体与VO之间相互转换的代码。事实上,这种方式只适合将表现层和业务层部署在同一台物理服务器上的小型应用。而对于大型应用和更复杂的应用这种方式将不能满足需要。因为:
1. 业务逻辑可能不再只包含在业务层。开发员可以在表现层操作业务实体,因此业务逻辑就被分散到了不同的地方(这对系统的维护来说简直就是一个梦魇)。这样不能将业务层和表现层清楚明白的分离开。
2. 当表现层运行在另外一台物理服务器上(这和系统使用其他富客户端情况相同)的时候,系统不得不系列化业务实体的所有属性并通过网络传递给表现层,这将影响系统的性能。比如要将一组订单的主要信息用列表在表现层展示给用户,在这种情况下,你不必将这些订单实体的所有属性值传递到客户端。在表现层需要显示的可能只需要每个订单实体的订单编号,订单日期和总金额信息。随后用户需要查看某个特定订单的详细信息时,此时只需要将这个订单的所有属性序列化然后传递到表现层。
3. 将所有实体信息都传递到表现层会引入数据安全风险。你希望客户应用访问到你雇员实体中的薪资信息或订单实体中的利润信息吗?
VO对象提供了一个解决所有这些问题的方案。是的,你只需要编写很少的一点代码,作为汇报,你将获得一个透明的与表现层更具交互效率的业务层。在客户端你可以将VO看做一个或多个相关业务实体的受控的视图。
提示:对实体和VO对象之间的相互转换AndroMDA提供了基本的支持功能,你将在本手册的相关章节看到。
服务对象和Hibernate会话:
由AndroMDA产生的应用系统中另外一个重要的问题:服务方法和Hiberante会话具有很紧密的关系。在我们讨论这个问题之前,我们必须将业务方法更底层的一些问题先展开讨论。Hiberante会话是一个运行时对象,允许应用系统读取,更新和删除数据存储中的业务实体和在数据存储中创建业务实体。当Hiberante会话对象处于开启状态,相关的业务实体被加载到会话中,你可以通过实体之间的关联关系从一个实体导航到另一个实体。如果某个相关的业务实体还没有被加载到内存中,而你正需要使用他,Hiberante会自动地帮你把这个对象加载到内存中来(这个通常被成为延迟加载)。然而当你关闭Hiberante会话,先前被Hiberante会话对象加载到内存的业务实体变成游离状态的对象,也就是说Hiberante不再知道这些业务对象以及他们之间的关联关系了。你当然可以自由的引用这些业务实体对象,但是Hiberante不再为你加载那些内存中没有加载的而你需要导航到的业务实体对象(对象导航失效,译者添加的)。当你还使用Hiberante的对象导航方式获取没有加载的业务实体对象时,系统会抛出延迟加载异常。
现在我们明白了Hiberante的导航原理,那我们继续深入讨论业务方法和Hiberante会话对象之间的关系吧。当客户端应用调用一个业务方法时,一个新的Hiberante会话会被自动开启。同样,当退出业务方法时,相关的Hiberante会话会被自动关闭。换句话说,Hiberante会话的生命周界限为业务方法的开始调用和结束调用之间。因此,在整个业务方法调用期间相关的业务实体对象将被加载到Hiberante会话中,但是一旦业务方法调用完毕,这些被加载的业务实体对象立刻脱离和Hiberante会话的关系。这样导致的结果:如果你的服务方法返回的是业务实体对象,客户端应用必须非常小心,不要去访问那些没有被加载到内存中的关联实体对象。要避免这些混乱,只要你遵循上节推荐的方案:在Hiberante会话开启的时候将客户端需要的信息从相关的业务实体对象中抽取到VO对象中,并将VO对象作为调用的返回值。通常,可以将业务方法看成是业务逻辑处理边界,在业务方法中完成所有的业务逻辑,最终返回VO对象。
由于业务方法和Hiberante会话的这种紧密关系,客户端应用不要试图绕过业务层直接和数据访问层交互。当然你可以这样做,但是不久你将身下困境。
现在你明白了AndroMDA的一些基本原则。接下来我们将讨论我们用于演示开发的DEMO系统。