UML软件工程组织

[保险构架分析]以不变架构应多变业务
出处:计算机世界报  作者:孟冬冬

财产保险行业业务具有以下特点:

1.保险险类、险种、产品众多

财产保险公司往往有包括企财险类、家财险类、责任险类、工程险类、车险类、船舶险类和货运险等几十个险类,上百个甚至几百个业务险种。这些险类险种既有共性,又有特性,如何将这些共性和特性有机地组织在一起是我们必须要有效解决的问题。

2.全流程业务需要

财产保险业务往往包含了投保、承保、批改、理赔、收付、财务等多个业务处理环节,同时还要通过挂接核保核赔管理和单证管理功能来降低企业的经营风险。提供多种统计分析与查询接口实现业务数据的统计分析,为企业经营决策提供及时、有效的支持和帮助。为统一架构与开发规范,降低保险公司的开发和维护成本,设计的技术架构必须能满足众多子系统的业务需求与技术要求。

3.新产品上线要求时间短

保险公司为了抢占市场,争夺客户,从研发推出新产品到产品上线往往只有一周甚至更短的时间,这对我们的系统架构提出了极高的要求。

4.行业高速发展,业务多变

保险行业是个高速发展的行业,业务多变,这是当前保险行业的特性决定的,我们只能去适应这些变化。所以,要求我们的架构必须具备很强的应变能力。

5.多语言支持

随着保险业的逐渐对外放开,越来越多的外资保险公司成为我们的客户。多语言支持成为这些客户对我们系统的基本要求之一。

当然财产保险行业还有其他一些特点,如全国大集中数据管理方式、总公司-分公司分支机构的管理模式、无纸化单证管理等等。作为财产保险公司的行业解决方案,系统必须能够适应以上这些行业特点,满足财产保险公司向用户提供新业务、新服务,适应市场竞争的需要; 满足各地区业务的变化性,适应地方性险种管理的需要。

从保险的定义出发,保险业务领域可分为投承保、批改、理赔等多个业务环节,针对样本程序,本文仅介绍承保业务。承保是保险业务的开始,承保信息关系到保单能否生成、与投保人能否签订合同、能否出具保单等。本样板程序以保险领域中“投保处理”环节作为参照实现,所以我们此处仅针对投保单相关的数据模型进行重点说明。

数据模型

“投保处理”环节涉及到了用户投保录入时的众多信息元素,包含了基本信息、标的信息、险种费用信息、条款信息、共保信息等五大类。投保录入主要涉及到四个主要的实体对象: 投保单主表、投保单险种表、标的主表、标的物险别责任表。除了这四个主要实体对象之间存在着一对多的对象关系外,每个实体对象还关联着众多的从属对象。

投保单主表是整张投保单的概括信息,它的相关从属表有投保兑换率表、投保单条款表、保险关系人表、收费计划表等; 投保单险种相关表描述的投保单项下各险种的相关信息,当投保单中存在多险种时,险种表描述多条险种信息,它的相关从属表有投保单保额保费表、险种条款表、险种费用表等; 投保单中的标的信息放在标的相关表中进行分类描述,以区分不同险种下的不同标的,它的相关从属表根据险类的不同有财产险标的信息、车险标的信息、动态标的信息等等; 标的险别责任相关表是对投保单中标的最明细的描述。它的相关从属表有标的物责任条款表、险别责任附加费表、险别责任免赔额表、险别责任赔偿限额表等。

总体架构

本着“不重复造车轮但也绝不依赖于任何第三方框架”的设计思想,我们独立设计开发了自己的基础框架体系SinoSoftFrame,在此SinoSoftFrame框架体系上,在部分层面引入一些优秀的开源产品,集成到我们的框架体系SinoSoftFrame中。这样,当已集成的产品在技术和效率上无法满足我们的业务需要时或在某个层面有更好、更快、更有效的新产品时,我们可以很容易地从SinoSoftFrame中完成新产品的升级替换,而对已开发完成的业务实现代码不产生任何影响或将影响降到最低。SinoSoftFrame架构基于J2EE规范实现,主要分为三层: Web层、业务层、持久层。

Web层采用MVC模式,主要任务是接收用户从页面提交的请求和最终返回处理结果。对于处理用户请求来讲,Web层的任务是读取用户提交的表单数据,把HttpServletRequest中的表单数据和请求参数封装到数据传输对象DTO中供业务层处理; 对于返回处理结果来讲,Web层的任务是把业务层处理完毕后返回的数据传输对象DTO返回给JSP页面展现给客户。

业务层主要完成业务逻辑的实现。如业务数据校验、业务逻辑处理、事务管理、记录业务处理日志、抛出业务处理异常等任务。

持久层仅用来完成业务数据持久化和查询读取,这里采用关系型数据库来完成数据的持久化保存,因此持久层主要完成数据库的CRUD(增、删、改、查),同时包含对存储异常的处理等任务。

SinoSoftFrame通过模拟Spring的实现机制建立了自己的容器实现机制,并通过定义接口、扩展基类等方法将对第三方依赖的内容封装到SinoSoftFrame中,从而实现与第三方框架的解耦。下面重点说明一下在架构设计的三层上具体采用的实现方式或开源框架。

因Web层确定采用MVC的设计模式,而软件开发领域有很多优秀的MVC开源框架,如Struts、WebWork2、Spring MVC等等,但也各有其优缺点。SinoSoftFrame的Web层实现选择了Struts,原因主要是基于它历经6年的不断成熟、它的稳定开发团队、它庞大的社区、用户和程序员基础。页面展现仍采用了传统的JSP+Taglib的实现方式。毕竟开发成本也是架构设计和选型要考虑的重要因素之一。

业务层框架的设计要求是增加模块或代码的复用性,降低业务类之间的耦合,减少程序修改带来的“涟漪”效应。在SinoSoftFrame的业务层我们选择了Spring。Spring是一种无侵入式的轻量级框架,可以用简单的POJO去完成接口类的定义及实现的调用,绝大多数业务对象都不需要依赖于Spring;可以很容易对业务层进行单元测试; 它促进程序员养成好的编程习惯(把对接口编程而不是对类编程的代价几乎减少到零)。当然,Spring框架带给我们的优势不只以上这些,它就像系统的粘合剂,对系统各个层面各个环节的功能、实现框架都提供了无缝的支持。不过,最主要也是最重要的还是Spring的Ioc模式实现(Ioc通俗来说,就是在编制程序时,只要写被调用者的接口代码,具体子类实例可通过配置实现)。

SinoSoftFrame选择了Hibernate作为持久层实现。Hibernate是一种Java语言下的对象关系映射解决方案。

它为面向对象的领域模型到传统的关系型数据库的映射,提供了一个使用方便的框架。它的设计目标是将软件开发人员从大量相同的数据持久层相关编程工作中解放出来。Hibernate不仅负责从Java类到数据库表的映射(还包括从Java数据类型到SQL数据类型的映射),还提供了面向对象的数据查询检索机制,从而极大地缩短了手工处理SQL和JDBC的时间,而且它不会强迫修改对象的行为方式,不需要实现任何框架要求的接口。惟一需要做的就是创建一份XML“映射文档”,告诉框架你希望能够保存在数据库中的类,以及它们如何关联到该数据库中的表和列,然后就可以要求它以对象的形式获取数据,或者把对象保存为数据。同时,它可以支持多达十六种数据库,包含企业级常用的Oracle、DB2、Informix、SQLServer、Sybase等。SinoSoftFrame系统架构如图1所示。
 

 同时,为了提供最佳的用户体验,SinoSoftFrame框架中还引入了Ajax的DWR实现,加上Ajax的调用层次后,系统调用架构如图2所示。
 

 辅助工具

● 代码生成工具JToolPad

设计师设计框架的目的是为了解耦、应变、统一规范、跨平台、支持多语言,但程序员眼中的好框架更多的则是:简单易用、快速开发。而SinoSoftFrame框架包含了三层,进行应用系统开发的程序员要面对众多的接口和实现类以及多个配置文件,显然并不简单。为此,我们独立开发了辅助代码生成工具JToolPad,用以生成SinoSoftFrame框架中的部分类和配置文件。为了从程序员的角度查看该架构,我们将JToolPad可以生成的类和配置文件以及框架本身提供的基类去掉后的系统架构图如图3所示。图3是程序员开发应用系统时的框架结构,而针对数据库应用系统中大多数的单表增、删、改、查操作,JToolPad还能生成更多的常见类及代码,如图4所示。



 从图4可以看到,程序员在结合JToolPad工具使用SinoSoftFrame框架时,大多数情况下都只需要完成Web层的页面控制跳转Action及业务层的接口和接口实现类即可,当然还有少不了的JSP页面和Action配置文件。如果程序员还觉得麻烦,JToolPad甚至还可以根据实现类直接生成对应的接口类(当然从设计的角度出发,不建议这么做)。
 

 ● 自定义标签库

为了进一步提高开发速度、统一页面规范,SinoSoftFrame框架中提供了多种自定义标签,如分页导航条、通用操作命令按钮、下拉列表、多语言自动支持、代码选择域、用户自定义风格等。

以分页导航条为例,开发人员只需在页面中相应位置嵌入一段简单的标签库代码即可在页面上显示风格统一并可自动实现上页、下页、第一页、最后一页、跳转到指定页的分页导航条。

● 基类及常用工具类

为了易于扩展SinoSoftFrame中各层的功能,也为了能通过AOP的方式完成业务的共性操作,如日志、权限检测等等。SinoSoftFrame在各层的基类中都提供了丰富的功能,如SQL权限的自动封装、功能权限的判断与检测、险种代码的自动替换、调试的Log自动输出等。

同时,SinoSoftFrame还提供了专门针对新版SinoSoftFrame框架开发的工具类,如页面参数的封装(单一对象封装及List对象自动封装)、Hibernate的增强处理等等。

● 业务通用组件

针对财产保险行业的领域特点及行业通用需求,SinoSoftFrame中还特意提供了很多业务通过组件,有用于页面的通用组件,如: 嵌套多行输入域、双击代码选择域、多语言自支持等。也有用于系统后台处理的通用组件,如: 权限管理、影像管理、打印管理、代码管理、工作流管理等。这些组件有的是通过直接调用类的方式实现,有的是通过标签库实现,大粒度的组件则是按组件的使用规则和使用方法实现。

● 引入的其他开源框架

针对应用系统开发中的特定问题框架也引入了其他的优秀开源框架。数据检验采用了Validtor校验框架,通过配置文件就可以对页面的输入域和多行数据域配置校验规则; 在使用Ajax为用户提供最佳体验方面,采用了DWR框架; 系统安全认证采用了Acegi,Acegi是在Spring的基础上实现的一套安全认证框架; 任务调度采用了Quartz调度框架。

链接:实现范例

我们通过“投保单保存”的一个实际调用过程说明一下SinoSoftFrame的具体实现。

● Web层信息录入

我们将信息元素按业务分类组织在多个标签页中,如: 基本信息、标的信息、险种费用信息、条款信息、共保信息等。每个标签页中包含了该类的主要录入元素。投保相关的页面通过标签的形式组织在一起,其中< mpc:page>标签库包含的内容在页面中的展现就形成了投保页面上的标签页。其中每个标签页中的内容又根据页面信息分类的不同包含在不同的JSP页面中,通过< jsp:include>标签库有机地组织在一起。

针对保险行业系统的国际化要求,JSP页面基本上都是用STRUTS标签以及自定义标签来写的。

● Struts配置文件相关定义

JSP页面提交后交由Struts的Action处理,相应的处理类定义在配置文件app-prpall-struts.xml文件中。需要特别注意的是配置文件中包含的通配符“$”的一行forward,内容如下:

< forward name="prepareInsert" path="/prpall/risk/$/EditFrame$.jsp business Type=Proposal"/>

该通配符是对保险行业产品众多特点的特殊处理,配合SinoSoftFrame的目录结构规范,开发人员只需在相应的Action中设置需要替换的险种代码即可很轻松、很容易地完成相应保险产品的自动跳转。

● Web层StrutsAction说明

系统应用框架根据Struts中的配置文件定义跳转到GuProposalAction类,系统应用框架根据Request中传入的actionType自动跳转到的相应方法中进行处理(处理方法与actionType同名)。

Web层处理类Action首先将页面参数组织到了投保单复合对象GuProposalDto中。SinoSoftFrame是通过paramUtils类完成页面变量到Dto对象和列表对象自动转换的。paramUtils是系统框架中提供的Request参数工具类。程序中简单地通过paramUtils的generateObject方法和generateList方法就可以完成页面参数到DTO对象间的自动映射。

● 业务层实现

投保单服务类由接口定义类和实现类组成。接口和实现的分离从一定程度上消解了依赖关系,具体实现可以在编译期间发生变化。GuProposal-Service及GuProposalServiceSpringImpl类图如图5所示。在GuProposalAction中调用业务层进行投保单保存的代码如下:

           图5 GuProposalService GuProposalServiceSpringImpl类图
           ServiceManager.getGuProposalService().insert(guProposalDto);

首先通过ServiceManager类的get方法来获得该服务接口类,然后通过insert()接口方法完成投保单的保存。方法的具体实现是在服务接口实现类中完成的,系统编码中引用的是接口类,而接口的实现类是由SinoSoftFrame在运行期注入的。接口和实现类的对应关系通过配置文件App-prpall-service.xml定义。

● 持久层实现

持久层主要由两部分构成: 数据访问对象DAO接口及其实现、实体对象PO。业务层通过调用持久层的DAO完成业务对象的持久化(即保存到数据库中)。实体对象PO是和业务模型一致用以完成数据库操作的业务对象,在进行投保单保存时主要有以下实体对象: 投保单主表、投保人及被保险人对象、投保费用。

系统框架要求实体对象必须遵从如下要求: 每个实体对象都必须继承于自身的实体Base类(该实体Base类是通过工具自动生成的);为实体对象增加不需要持久化的扩展属性时,在实体对象中增加; 严格保持Base类与数据业务模型(即数据库结构)的一致。

Hibernate完成业务对象的持久化是通过hbm配置文件将对象属性和数据库表中的字段对应来自动完成的,因此配置文件hbm是不可缺少的(可以由工具自动生成)。

持久层DAO的设计模式和业务层类似,也是将接口和实现分开实现了持久层的解耦。接口类中定义了每个业务对象的持久化操作,实现类中实现了具体的持久化实现代码。通过持久层的解耦,有效地解除了应用系统对SinoSoftFrame中引用的持久层框架的依赖,同时更有效地支持了各种存储形式,包括自定义的存储方式。

通过类图可以看到,每个持久化对象都会对应一套DAO对象(该套DAO可以通过工具自动生成)。如果需要编写自定义的数据库操作,可以在DAO的接口和实现层中进行扩展(不需要修改DAOBase类)。可以看到,只需调用Dao层的insert方法即可将投保单持久化对象保存到数据库中。


版权所有:UML软件工程组织