1、大型 J2EE 项目中异常处理机制的设计绪 论随着计算机信息化技术在国内的普及,许许多多企业应用也如雨后春笋般的随之诞生。Sun 的 J2EE 平台自诞生以来就着力于解决企业应用的各种复杂性,例如他提出了全局事务的概念解决了分布式数据库间的事务同步,JCA (Java Connection Adaptor)连接器的概念解决了异构系统如何使用 J2EE 容器提供的特性等功能,JMS(Java Messaging Service)用来处理 Java 平台之间消息发布,EJB 的概念专注于架构基于分布式系统企业应用等。这些“重型武器”着重于解决了系统架构级别的应用复杂度的同时,也留给了我们一个空白,
2、那就是如何去解决业务逻辑带来的系统复杂问题,例如信息安全,系统性能,异常处理等。有些问题我们可以通过应用模式来处理,比如说 Martin. Fowler 的“企业应用架构模式”一书,其中就归纳了很多关于企业应用设计方面的设计模式,他把企业应用会遇到的问题归纳成各种模式例如“对象-关系行为模式”,“数据源架构模式”,“Web 表现模式”等。这些模式的提出有益于构建基于松散耦合同时易于扩展的应用系统,但有些问题是和系统业务复杂程度有关的比如说企业应用的异常处理。业务逻辑比较简单的系统不需要对异常做专门的架构设计,但是对于大型 J2EE 企业应用而言,由于其自身业务的复杂,所连带产生的异常消息量也是
3、十分巨大的,如何处理这些大量的异常消息,如何收集业务操作中所发生的所有异常情况,如何使得每一笔业务操作都有特定的异常处理机制 ,可以想象随着应用系统被用户的逐渐接受,解决这些问题将会变得越来越迫切。传统的处理异常的方法,无非就是增加大量的 try catch 块来捕获异常,这样做的缺点在于会使得代码迅速膨胀同时难以后期维护,而且异常的消息很难被收集起来统一显示给客户,实际上企业异常的处理所涉及到的不单单是异常的捕获和收集,还包括异常消息的国际化,异常的回滚和异常的分类等等,业内在这方面给我们提供了很好的平台和很多现成的工具,例如 Spring 的 AOP 的(Aspect Oriented P
4、rogramming)框架,AOP 是 Aspect Oriented Programming 的简称,又名面向切面编程。它是软件工程发展到一定高度的一种对事物的抽象,也是对 OOP 的强力补充。它的作用就是对类实现非侵入性的增强。如果说 OOP 是提供了一种纵向继承结构的编程方式的话,AOP 就是提供了一种横向切面方式的编程方法。目前在 J2EE 领域正在被广泛使用,例如事务,日志,权限验证等,其中比较有名的基于 AOP 的实现框架有 Spring 的声明式事务管理,和Spring-Acegi 对权限的验证。除了 Spring 提供了 AOP 的实现外,IBM 的 AspectJ 提供了一套
5、面向切面的编程语法,其他的例如 Jboss 公司和 Oracle 公司都分别在他们的应用服务器中集成了 AOP 功能,Sun 的 EJB3 也提供了对 AOP 的支持,可以说随着时间的发展,基于 AOP 的应用将会越来越多的受到重视和发展。由于 AOP 天生就有在不改变原来的代码的前提下对类提供增强的特征,完全符合企业应用中对异常处理的需要。AOP 框架虽然提供了一个很好的面向切面编程接口,但是需要实现一套基于大型J2EE 系统的异常处理框架,还需要对企业异常处理的机制有深入的研究和了解。企业应用系统的设计需要考虑很多架构方面的问题,而异常处理往往容易被人忽视,人们普遍的都愿意关注业务的主要流
6、程,而实际上业务的主要流程只占代码总量的 1/3,而其他2/3 的代码往往都是处理校验,处理异常和处理分支代码,如果能够有一套框架能够把大部分的异常处理的代码从业务逻辑中提取出来,将能够大大的减少代码的总量,从而提交给客户更加优秀更加效率的系统。IEC (Interface of Error Collector) 是作者基于自己对企业异常的理解,利用 Spring 的 AOP 实现的用来处理大型 J2EE 项目中异常情况的框架,它同时提供了对外的接口用来收集异常,而异常的捕获则全部交给框架来处理,她能够捕获并收集用户在执行一笔业务的过程中所发生的异常消息,同时提供国际化的支持,而且程序员不需要
7、对原生的业务代码产生很大的改动,大大降低了代码之间的耦合。虽然一个企业应用需要考虑的东西很多,但是前期任何一个方面的忽视都会导致后期大量的成本来弥补,异常处理往往就是一块容易被忽视的领域。作者实现的这套IEC 的框架,是希望能够利用实际工作项目的机会同时结合自己对这个领域的思考做出一些贡献,同时起到一个抛砖引玉的作用。研究背景和意义目前国内外的所有 J2EE 的程序主要基于 SSH(Struts+Spring+Hibernate)的三层框架,但是分层带来解耦特性的同时,也带来了传统开发中所没有面临过的问题,比如说层与层之间异常的收集和处理。传统的软件开发方式让程序员大量地关注业务的主要流程而忽
8、视业务的出错流程,但是在大型的软件中我们不但需要处理大量的异常,同时每一种类型的异常对主业务流程的影响也是不一样的。如果没有一套完整的异常处理体系的支持,不久系统就会陷入“异常“混乱的境地。由于对于如何处理企业异常很少有理论来指导这块领域,使得大部分的项目都有自己的一套处理方法,比如有些项目选择将异常信息用资源文件控制,然后通过一个抽Page | 3象异常的接口对资源文件进行读取,这样做的好处是只解决了国际化的问题,但是并没有从实际上解决对异常的分类和分级,还有一些项目选择将异常保存到数据库,同时增加级别字段对异常进行处理,这样做的好处是程序的异常确实有了更加细致的描述,但是如何收集异常以及怎
9、么处理不同种类的异常情况,各个项目没有形成一套可以相互参考和借鉴的理论和设计体系。事实上一个基于一个 J2EE 的项目中异常可以分成以下几类: 用户输入异常 程序业务逻辑异常 模型校验异常而每一种类型的异常所处的层次都各不相同,比如用户输入类型的异常就处在J2EE 模型的最高层(action level),业务逻辑异常通常放在 service 层,而 model 层的模型校验异常就负责处理具体的持久化类型的异常情况,针对每一种不同类型的异常,程序都应该提供不同的处理机制。在 J2EE 项目中有很多的开源可以提供我们帮助,比如 Spring 的 AOP 框架,它就充分允许我们对 J2EE 容器中
10、的业务对象作管理和拦截,利用拦截器的技术,我们可以充分的分析和处理异常,所以从理论上来讲一套基于拦截器的异常处理框架是可行的,其次我们还有很多第三方的专门针对用户输入异常处理的框架 比如说 Apache 的 common-validation 包等。所以目前不管是从业务的需要还是从技术的角度来讲,都具备了提供一套比较完整的异常处理框架的条件。分析一下现代大型 J2EE 项目中在程序异常处理所普遍遇到的异常处理方面的问题和难点。拟解决以下几方面问题:1. 业务逻辑复杂,异常情况众多这个主要发生在大型的项目中,由于系统自身的复杂性往往一笔业务会牵涉到数十种出错的逻辑,而且在这样的项目中客户大都参与
11、到实际的需求分析中。客户会和需求分析人员一起归纳出某一笔操作中可能出现的异常,以及他们根据业务情况所提出的解决放案。2. 客户对异常有较严格的要求,希望对不同的异常有不同的处理所有的异常都是有级别的,比如某些一场属于输入类型的异常,某些异常输入业务逻辑的异常,某些异常属于模型自身的异常(不变量异常),程序需要处理大量异常的同时,对异常作归类。3. 客户希望能够收集一笔业务操作中所有的异常,然后统一解决在大型的项目中,一笔业务操作往往涉及到很多模块的协同操作,而在这个过程中往往会发生很多的异常,有一些异常我们需要提示用户,而有一些异常则需要回滚整个业务操作,如果我们能提供一套完成的异常处理框架,
12、我们就能够对用户在一次操作中所发生的异常做收集和展现,从而为用户节约了操作时间。 论文研究主要内容本文是基于目前作者主要从事的实际项目,总结和归纳出一套适应大型 J2EE 项目的异常处理框架。在本文中作者拟从以下几方面来进行研究:1. 企业异常的定义和分类。主要定义了异常在企业应用中的类型,哪些是属于业务异常,哪些是非受控型的异常(例如网络故障)。同时分析了异常在企业应用的不同层级中处理的方式也是不同的。2. 企业异常处理的需求。总结了大型业务系统中,业务员往往需要从异常反馈消息中获得的提示以及如何将客户和软件分析人员一起有效地参与到企业异常消息的定义中。3. 异常框架如何处理异常情况。定义了
13、一个专门处理异常的框架有哪些地方是需要重点关注的,以及他需要满足的功能。4. 通过 AOP 的框架捕获异常。提出了基于 AOP 的思想可以非侵入性的捕获企业的异常,同时做到对业务代码的侵入性降到最低。5. 异常消息的国际化支持。提出了利用资源文件的方式来处理国际化支持,这个主要针对大型的需要国际化支持的业务系统。6. 异常收集机制的设计以及线程安全的需要。提出了一套线程安全异常收集接口,它可以收集企业应用中各个层次发生的异常。论文的组织结构本文一共分为五章第一章 简要概述了论文的内容以及章节安排Page | 5第二章 主要介绍了基于 J2EE 的 MVC 三层模型以及他的相关概念。分析了业内一
14、些异常处理的方式,同时定义了企业异常的概念和异常处理框架需要满足的功能。第三章 提出了异常处理框架的概念以及框架需要实现的功能,同时针对每一种需求提出了作者的设计思路。第四章 以作者目前从事的项目为基础,介绍了 IEC(Interface of Error Collector)异常处理框架的总体设计和一些核型功能的详细设计机制。第五章 总结了研究内容和成果,定义了下一步的工作重点异常处理及传统 J2EE 体系结构分析J2EE( Java 2 Platform, Enterprise Edition) 是 Sun 提 出 的 一 套 应 用 开 发 技术 架 构 , 它 在 简 化 了 传 统
15、企 业 应 用 开 发 的 同 时 , 规 范 了 开 发 、 部 署 的 环 节 , 进 而 缩短 了 开 发 的 成 本 , 提 高 了 组 件 的 再 用 性 。 由 于 它 具 有 高 可 伸 缩 性 、 灵 活 性 和 易 维 护 的特 点 , 从 一 开 始 就 受 到 了 BEA、 IBM 以 及 Netscape Application Server 等 业 内 知 名IT 供 应 商 的 支 持 。 它 的 优 势 主 要 可 以 体 现 在 :标 准 的 设 立 : J2EE 平 台 为 许 多 的 企 业 应 用 领 域 所 关 注 的 问 题 提 供 了 标 准 , 比
16、如 数 据 库 连 接 , 面 向 消 息 的 组 件 , 通 信 协 议 及 互 操 作 等 。开 发 的 高 效 : 由 于 J2EE 规 范 充 分 划 分 了 开 发 的 职 责 , 开 发 人 员 只 需 要 关 注 自己 领 域 内 的 逻 辑 , 而 无 需 考 虑 诸 如 状 态 管 理 , 事 务 连 接 和 分 布 式 应 用 等 非 常 繁 琐 的 问题 , 通 过 将 这 些 问 题 留 给 每 个 中 间 件 的 供 应 商 来 解 决 , 使 得 开 发 的 效 率 大 大 提 高 , 产品 也 更 加 具 有 质 量 。支 持 异 构 环 境 : 基 于 分 布
17、式 开 发 的 J2EE 完 全 不 依 赖 于 所 在 计 算 机 的 环 境 , 由于 Java 天 生 的 具 有 的 跨 平 台 的 能 力 , J2EE 可 以 部 署 在 每 一 台 装 有 Java 虚 拟 机 的 电脑 ,同 时 J2EE 的 标 准 也 允 许 客 户 与 J2EE 兼 容 的 第 三 方 组 件 , 极 大 地 增 加 了 现 有 IT环 境 的 利 用 率 。可 伸 缩 性 : 未 来 软 件 的 趋 势 是 软 件 平 台 自 身 要 满 足 客 户 不 断 增 长 的 需 求 。J2EE 平 台 能 提 供 极 佳 的 系 统 可 伸 缩 性 。 它
18、可 以 被 部 署 到 任 意 一 台 台 式 机 中 , 例 如 大型 应 用 系 统 基 于 稳 定 性 的 考 虑 , 往 往 选 择 Linux 与 Unix 等 操 作 系 统 , 而 J2EE 可 以适 应 任 何 一 种 操 作 系 统 。 同 时 由 于 支 持 J2EE 中 间 件 的 供 应 商 很 多 , 在 大 型 分 布 式 的应 用 环 境 中 , 它 能 给 客 户 提 供 更 广 泛 的 负 载 平 衡 策 略 , 满 足 由 于 业 务 需 要 带 来 的 性 能问 题 。高 稳 定 性 和 可 用 性 : J2EE 具 有 高 度 的 平 台 稳 定 性 ,
19、 同 时 结 合 一 些 稳 定 的 操 作系 统 例 如 Sun Solaris、 IBM OS/390 可 以 实 现 每 年 只 需 5 分 钟 的 停 机 时 间 , 为 企 业应 用 的 连 续 性 和 稳 定 性 提 供 了 强 有 力 的 保 障 。J2EE 层次模型Sun 为 了 解 决 当 时 C/S (client/server)二 层 模 型 难 于 升 级 和 维 护 的 缺 点 , 采 用分 布 式 的 概 念 , 提 出 了 四 层 模 型 , 将 各 个 组 件 按 照 他 们 所 在 的 层 分 布 在 不 同 的 计 算 机上 , 它 们 分 别 是 : 客
20、户 层 组 件 :J2EE 的 客 户 层 组 件 包 括 用 户 访 问 J2EE 平 台 的 接 口 , 可 以 通 过 Web 的 方 式也 可 以 通 过 Swing 等 非 Web 的 方 式 去 处 理 。 Web 层 组 件包 括 JSP( Java Server Pages) 和 Servlets。 业 务 逻 辑 组 件业 务 逻 辑 组 建 , 主 要 服 务 于 特 定 领 域 的 商 业 应 用 , 它 是 由 EJB( Enterprise Java bean) 组 成 的 EIS 层 组 件由 于 商 业 应 用 的 需 要 , J2EE 平 台 可 以 和 异 构
21、 的 平 台 通 信 , 用 来 做 数 据 交 换 或者 是 满 足 特 定 业 务 逻 辑 的 需 要 。下 图 描 述 了 四 层 模 型 的 基 本 关 系 :Page | 7Web ContainerWeb Browser Swing ClientJSP/ServletEJB ContainerSession EJBJSP/ServletEntity EJBEIS 系统DB1 EIS 层业务逻辑层Web 层RMI客户 层从 上 图 看 到 J2EE 的 设 计 目 标 就 是 基 于 分 布 式 的 , 这 种 设 计 模 式 带 来 了 可 移 植 性 优 势的 同 时 也 带 来
22、 了 复 杂 性 的 大 幅 度 提 高 , 由 于 层 与 层 之 间 的 通 信 协 议 都 是 延 续 了 J2SE的 RMI 服 务 模 型 ( Remote Method Invocation) 单 单 处 理 RemoteException 的 代码 就 有 和 业 务 代 码 产 生 高 度 的 偶 合 , 同 时 强 制 企 业 应 用 分 布 式 也 是 不 合 理 得 , 因 为 大部 分 业 务 逻 辑 组 件 并 不 打 算 被 分 布 , 同 时 分 布 式 组 件 还 容 易 产 生 各 种 问 题 , 例 如 网 络问 题 引 发 的 系 统 异 常 , 等 ,这
23、 些 复 杂 性 的 引 入 实 际 是 增 加 了 系 统 的 不 稳 定 性 。 事 实 上业 内 的 J2EE 开 发 很 少 采 用 这 种 模 型 , 由 于 近 几 年 轻 量 级 容 器 ( Spring) 的 大 面 积 推广 , 使 得 在 不 损 失 传 统 架 构 优 势 的 前 提 下 , J2EE 的 开 发 模 型 已 经 更 加 趋 向于 向 敏 捷 和 易 扩 展 转 化 。基于轻量级容器架构的 J2EE 模型 由 于 传 统 的 架 构 有 很 多 缺 点 , 业 内 普 遍 采 用 以 下 的 架 构 , 作 者 称 之 为“基 于 轻 量 级 容 器 的
24、J2EE 架 构 ”MVC ArchitectureWeb Browser Swing ClientJSP/ServletEIS 系统DB1 EIS 层业务逻辑层Web 层客户 层轻量级容器Service LayerORM Layer这 种 基 于 这 种 架 构 的 企 业 应 用 把 业 务 逻 辑 层 和 Web 层 合 并 在 一 个 JVM 中 , web 层通 过 一 个 MVC 的 框 架 和 业 务 层 的 门 面 代 理 去 访 问 业 务 逻 辑 层 , 两 层 合 并 的 优 势 在 于大 大 的 简 化 了 企 业 应 用 的 开 发 , 同 时 由 于 一 些 轻 量
25、 级 容 器 的 成 熟 , 比 如 Spring 和PicoContainer 等 , 业 务 逻 辑 的 代 理 可 以 很 方 便 的 被 web 层 调 用 到 , 而 不 需 要 依 赖具 体 的 实 现 , 同 时 从 性 能 角 度 讲 , 这 种 架 构 更 加 易 于 扩 展 和 集 群 。企业异常的分布Page | 9基 于 轻 量 级 的 架 构 是 目 前 比 较 流 行 的 一 种 J2EE 架 构 , 基 于 这 种 架 构 的 企 业 应用 异 常 也 主 要 分 布 在 客 户 层 , web 层 , 业 务 逻 辑 层 以 及 EIS 层 。客 户 层 的 异
26、 常 通 常 指 客 户 端 的 校 验 逻 辑 异 常 , 比 如 在 提 交 一 笔 业 务 之 前 客 户 端需 要 满 足 的 提 交 前 校 验 , 值 空 , 大 于 0 小 于 0 等 , 一 般 情 况 下 这 种 异 常 的 处 理 都 比较 迅 速 而 且 不 需 要 通 过 服 务 器 , 例 如 很 多 企 业 应 用 都 利 用 JavaScript 去 做 客 户 端 的校 验 , 这 样 做 的 好 处 是 用 户 无 需 等 待 服 务 端 的 响 应 来 判 断 这 次 操 作 是 否 正 确 , 缺 点 是很 多 客 户 端 的 校 验 是 不 安 全 的
27、, 虽 然 他 能 够 减 轻 服 务 器 的 校 验 负 荷 , 但 是 我 们 可 以 通过 修 改 客 户 端 的 校 验 逻 辑 来 强 制 信 息 提 交 到 服 务 器 , 所 以 这 个 时 候 如 果 服 务 器 没 有 相应 的 校 验 的 话 , 这 个 校 验 判 断 就 被 忽 略 了 , 这 是 一 种 非 常 危 险 的 操 作 , 也 不 被 提 倡 ,特 别 是 对 于 企 业 应 用 这 样 一 个 对 安 全 和 稳 定 信 性 要 求 很 高 的 商 业 系 统 来 说 , 任 何 绕 过校 验 的 方 法 都 应 该 在 一 开 始 设 计 的 时 候
28、被 考 虑 和 屏 蔽 掉 。 对 于 非 Web 的 J2EE 应 用 ,绕 过 客 户 端 异 常 的 校 验 也 是 十 分 简 单 的 , 只 需 要 反 编 译 相 应 的 源 代 码 , 然 后 编 写 自 己相 应 的 校 验 逻 辑 , 然 后 替 换 原 来 的 校 验 就 可 以 了 , 由 于 相 同 名 字 空 间 的 类 JVM 只 允许 有 一 个 存 在 , 所 以 自 己 编 写 的 校 验 逻 辑 很 容 易 覆 盖 掉 原 来 的 校 验 逻 辑 , 总 而 言 之 把关 键 的 校 验 逻 辑 放 在 客 户 端 是 十 分 不 安 全 的 一 种 解 决
29、 办 法 。Web 层 的 异 常 实 际 上 是 客 户 层 的 异 常 在 服 务 器 的 实 现 , 这 样 做 的 好 处 是 异 常的 处 理 更 加 安 全 , 也 可 以 支 持 复 杂 的 表 现 层 校 验 逻 辑 , 由 于 是 用 JAVA 编 写 的 校 验逻 辑 , 所 以 校 验 逻 辑 更 加 容 易 被 重 用 , 而 且 目 前 很 多 的 第 三 方 的 开 源 软 件 都 支 持web 层 的 校 验 , 比 如 说 common-validation, struts 的 DynaValidatorForm。 实 际 上有 过 J2EE 开 发 经 验 的
30、 人 都 知 道 任 何 的 异 常 都 是 数 据 流 造 成 的 , 而 从 客 户 层 到 web层 的 数 据 结 构 是 DTO( Data Transaction Object) 数 据 传 输 层 , Web 层 的 校 验 主 要是 对 数 据 传 输 层 做 校 验 。 如 图 所 示 :DTO客户层客户层校验HTML,JAVASCRIPT No-Web ClientWeb 层ServeltsWeb 层校验从 上 图 可 以 看 到 , 客 户 层 和 Web 层 之 间 的 交 互 需 要 通 过 一 层 DTO 来 包 装 ,关 于 如 何 校 验 DTO, 可 以 参
31、考 异 常 处 理 的 第 三 方 支 持 一 节 。业 务 层 的 异 常 包 括 很 多 , 在 JAVA 的 领 域 里 面 异 常 被 分 为 受 控 异 常 以 及 非 受 控异 常 , 所 谓 的 受 控 异 常 是 指 和 业 务 有 相 关 性 的 异 常 , 例 如 数 据 不 存 在 , 格 式 不 正 确 或者 数 据 不 合 法 等 , 客 户 层 可 以 根 据 从 业 务 层 返 回 的 异 常 中 得 到 明 确 的 异 常 提 示 然 后 做合 理 的 后 续 操 作 , 这 种 类 型 的 异 常 时 受 控 异 常 , 也 是 本 文 要 重 点 关 注 的
32、 一 种 类 型 的 异常 。 非 受 控 异 常 时 指 在 实 际 操 作 中 由 于 各 种 非 受 控 的 外 界 因 素 导 致 的 异 常 , 例 如 网 络故 障 又 比 如 在 EJB 的 环 境 中 , 要 求 客 户 处 理 的 RemoteException 这 中 类 型 的 异 常 ,如 果 从 后 台 抛 出 的 话 , 客 户 是 无 法 从 中 得 到 任 何 的 有 价 值 的 信 息 的 。 所 以 就 要 求 在web 层 有 一 个 前 段 的 控 制 器 负 责 处 理 所 有 从 也 业 务 层 返 回 的 异 常 , 前 段 控 制 器 的 作用
33、除 了 负 责 展 示 异 常 的 消 息 之 外 , 还 需 要 负 责 异 常 的 页 面 控 制 跳 转 。 业 务 层 需 要 处 理一 次 业 务 操 作 中 的 所 有 发 生 的 异 常 , 同 时 返 回 异 常 的 类 型 , 为 了 让 前 段 的 控 制 器 能 够有 效 的 识 别 异 常 的 类 别 和 异 常 消 息 , 针 对 大 型 的 J2EE 系 统 来 说 , 往 往 就 需 要 设 计 一个 类 型 很 庞 大 的 异 常 类 结 构 来 满 足 复 杂 的 业 务 需 求 。 别 且 由 于 还 混 合 了 一 些 非 受 控 的异 常 类 型 , 使
34、 得 从 业 务 层 到 web 层 的 异 常 返 回 情 况 变 的 十 分 的 复 杂 和 不 确 定 。受 控 异 常 从 业 务 逻 辑 层 的 校 验 层 中 抛 出 , 非 受 控 异 常 则 可 以 从 任 何 的 业 务 代 码中 抛 出 , 前 段 控 制 器 很 难 区 分 那 种 类 型 属 于 受 控 , 哪 种 类 型 属 于 非 受 控 的 。 这 就 需 要有 一 种 框 架 来 专 门 包 装 这 两 种 类 型 的 异 常 , 同 时 又 不 损 失 异 常 的 语 义 。Web层 业务逻辑层受控异常常非受控异常ServletsPOJOPage | 11EI
35、S 层 包 括 异 构 企 业 信 息 系 统 也 包 括 数 据 库 。 EIS 层 的 异 常 主 要 是 也 是 由 受 控异 常 和 非 受 控 异 常 组 成 的 , 比 如 业 务 层 需 要 通 过 web 服 务 去 访 问 另 一 个 系 统 的 对 象 ,从 而 执 行 一 些 业 务 操 作 , 在 这 个 过 程 中 远 程 接 口 有 可 能 声 明 抛 出 受 控 异 常 , 也 有 可 能由 于 底 层 的 复 杂 性 , 远 程 接 口 直 接 抛 出 了 RemoteException 也 是 很 有 可 能 的 。 但 是这 里 的 异 常 的 处 理 有
36、个 特 殊 的 地 方 就 是 事 务 , 如 果 通 过 JCA(J2EE Connector Architecture)的 连 接 方 式 的 话 , 事 务 是 可 以 传 播 到 异 构 系 统 中 的 , 但 是 这 个 也 要 特 定于 具 体 的 连 接 器 , 如 果 通 过 Web 服 务 方 式 的 话 , 事 务 是 没 有 办 法 传 播 的 , 如 果 通 过JMS 的 方 式 的 话 , 事 务 的 传 播 只 是 局 限 于 消 息 如 列 之 前 , 消 息 进 入 消 息 中 间 件 之 后的 事 务 是 不 受 权 全 局 事 务 控 制 的 , 这 就 给
37、 开 发 人 员 出 了 一 个 难 题 , 就 是 如 果 在 消 息 发送 之 后 , 程 序 出 现 了 异 常 , 怎 么 去 处 理 后 续 的 异 常 恢 复 。 如 下 图 简 述 了 业 务 层 和 EIS层 的 异 常 交 互 。传统异常处理的机制传 统 的 异 常 处 理 都 是 基 于 “抛 出 ”, “捕 获 ”来 实 现 的 。 抛 出 异 常 是 在 类 签 名的 时 候 声 明 的 , 这 种 类 型 的 异 常 是 受 控 异 常 ( checked) , 同 时 由 于 Java 语 言 也 支持 类 在 没 有 签 名 的 时 候 也 能 抛 出 异 常 ,
38、 这 种 异 常 叫 非 受 控 异 常 ( uncheck) 。 例 如 业务 系 统 中 需 要 定 义 一 个 接 口 ParcelService 用 来 保 存 Parcel 对 象 。 而 在 保 存 之 前 我们 需 要 查 看 对 象 是 否 已 经 存 在 , 这 里 的 已 经 存 在 不 单 单 是 数 据 库 记 录 的 重 复 , 而 是 含有 一 定 的 业 务 逻 辑 , 比 如 说 Parcel 的 所 占 用 的 pipeline 是 否 已 经 被 其 他 的 parcel 所业 务 逻 辑 层 POJOEIS 层DBEIS受控异常 非受控异常RMI-IIOP
39、使 用 , 如 果 是 的 话 接 口 就 会 抛 出 UnAvailablePipelineException, 这 个 时 候 的 异 常 就是 受 控 异 常 , 受 控 异 常 是 业 务 用 户 可 以 弥 补 或 者 修 复 的 异 常 。 如 下 代 码 段 :ParcelDao 是 ParcelService 关 联 的 一 个 数 据 库 操 作 的 代 理 类 , 在 执 行 保 存 parcel的 动 作 之 前 需 要 做 一 些 业 务 逻 辑 的 校 验 , 如 果 业 务 逻 辑 不 满 足 校 验 条 件 的 话 就 抛 出 异常 , 大 部 分 的 企 业 应
40、 用 都 是 采 用 这 样 的 逻 辑 。 ParcelDao 的 save 方 法 也 会 抛 出 异 常 ,例 如 数 据 库 连 接 过 期 , 或 者 网 络 断 开 等 , 这 种 类 型 的 异 常 就 是 非 受 控 异 常 。 这 个 例 子展 现 了 web 层 的 前 段 控 制 器 如 果 需 要 关 联 这 些 业 务 层 的 方 法 的 话 就 必 须 去 捕 获 这 些异 常 , 同 时 还 必 须 区 分 哪 个 异 常 代 表 哪 种 类 型 的 错 误 和 哪 些 异 常 是 受 控 的 而 哪 些 是 非受 控 的 。异常类型的划分从 业 务 的 角 度
41、来 看 , 所 有 客 户 无 法 恢 复 的 异 常 都 属 于 非 受 控 异 常 。 比 如 前 面 讲到 的 ParcelDao 的 save 方 法 有 可 能 抛 出 底 层 的 通 信 协 议 类 的 异 常 , 客 户 往 往 对 此 束手 无 策 , 所 以 传 统 的 异 常 处 理 机 制 需 要 明 确 在 一 个 应 用 系 统 什 么 类 型 的 异 常 时 客 户 无法 恢 复 而 需 要 交 给 框 架 处 理 的 。 比 较 合 理 的 一 种 划 分 如 下 :受 控 异 常 : 客 户 的 业 务 逻 辑 异 常 业 务 对 象 的 校 验 异 常 应 用
42、 系 统 安 全 检 查 异 常Page | 13非 受 控 异 常 : 远 程 方 法 调 用 异 常 系 统 异 常前 段 控 制 器 的 设 计前 面 介 绍 了 , 轻 量 级 J2EE 架 构 的 核 心 是 一 个 MVC 框 架 和 一 个 业 务 层 的 容 器 ,如 果 业 务 层 向 web 层 又 能 抛 出 受 控 又 能 抛 出 非 受 控 异 常 的 话 , web 层 是 如 何 处 理 的 ?web 层 通 常 都 有 一 个 前 段 控 制 器 , 前 段 控 制 器 的 作 用 就 是 捕 获 异 常 , 分 析 异 常 消 息 ,页 面 派 发 。 如 果
43、 从 业 务 层 抛 出 的 是 受 控 异 常 的 话 , 前 台 就 会 把 这 个 受 控 异 常 泡 状 包 装成 消 息 的 形 式 发 给 页 面 , 这 种 流 程 可 以 参 考 Struts 的 页 面 派 发 和 异 常 处 理 流 程 。 但是 这 里 就 引 入 了 一 个 问 题 , 如 何 区 分 受 控 和 非 受 控 的 异 常 ? 回 答 就 是 MVC 框 架 无 法区 分 , 因 为 框 架 没 办 法 确 定 哪 些 异 常 对 客 户 有 用 的 , 哪 些 是 没 有 用 的 , 所 以 一 个 设 计良 好 的 异 常 体 系 就 至 关 重 要
44、。 有 了 异 常 体 系 , 前 段 控 制 器 可 以 只 关 注 和 其 相 关 的 异 常类 型 , 而 把 非 受 控 的 异 常 类 交 给 更 高 层 的 控 制 器 处 理 。 这 样 前 端 控 制 器 的 体 系 结 构 应该 是 这 样 的 : ( 参 考 Template 设 计 模 式 )一 个 Baseaction MVC 前 段 控 制 器 的 基 类 , 从 基 类 派 生 的 子 类 AbstractAction 处 理和 业 务 无 关 的 , 但 是 特 定 于 框 架 的 一 些 工 作 例 如 非 受 控 异 常 的 处 理 , 前 面 已 经 介 绍
45、 过了 , 非 受 控 异 常 的 发 生 , 客 户 往 往 无 法 恢 复 , 必 须 联 系 系 统 的 管 理 员 , 而 这 个AbstractAction 就 负 责 处 理 非 受 控 的 异 常 。 而 特 定 于 具 体 业 务 的 具 体 前 段 控 制 器 , 可以 处 理 业 务 异 常 , 就 好 比 前 面 介 绍 的 UnAvailablePipelineException,由 于 这 些 都 是在 声 明 抛 出 的 , 所 以 前 段 控 制 区 需 要 手 动 的 写 捕 获 的 逻 辑 , 就 是 Java 里 面 最 让 人 头疼 的 try+catch
46、 处 理 块 。 那 前 面 的 ParcelService 声 明 抛 出 的UnAvailablePipelineException 为 例 , 前 段 控 制 器 必 须 有 如 下 代 码 :code : 前 段 控 制 器 异 常 捕 获 1tryParcelService.save(p);catch(UnAvailablePipelineException e)/执 行 错 误 分 析 和 页 面 派 发从 上 面 的 代 码 段 可 以 看 出 如 果 一 个 大 型 的 企 业 应 用 逻 辑 复 杂 的 话 , 前 段 控 制 器的 代 码 将 会 迅 速 的 被 大 量 的
47、 异 常 捕 获 代 码 所 侵 占 掉 , 针 对 这 种 情 况 , 可 以 通 过 合 理 的异 常 体 系 结 构 来 解 决 。异 常 体 系 结 构 的 设 计异 常 体 系 结 构 的 设 计 的 原 则 就 是 区 分 受 控 和 非 受 控 异 常 , 然 后 包 装 成 基 本 异 常体 系 结 构 中 的 基 类 。 前 面 讲 到 了 , 业 务 层 可 以 向 web 层 放 回 两 种 类 型 的 异 常 , 根 据这 个 特 点 企 业 应 用 的 异 常 体 系 结 构 可 以 设 计 成 如 下 :受 控 异 常 :BaseAppExceptionExcept
48、ionInvalidModelException BusinessCheckExceptionSecurityCheckExceptionPage | 15非 受 控 异 常 :BaseAppRuntimeExceptionRuntimeException程 序 如 果 有 特 定 的 业 务 异 常 比 如 UnAvailablePipelineException 可 以 完 全 继承 自 BusinessCheckException。 基 于 这 样 的 异 常 结 构 前 段 控 制 器 的 捕 获 代 码 将 被 大大 的 减 少 , 通 常 只 需 要 一 个 try+catch 块
49、 就 可 以 完 成 。code : 前 段 控 制 器 异 常 捕 获 2tryParcelService.save(p);catch(BaseAppException e)/执 行 错 误 分 析 和 页 面 派 发程 序 只 需 要 捕 获 一 个 BaseAppException 就 可 以 了 , 因 为 程 序 的 异 常 体 系 结构 决 定 了 任 何 的 受 控 异 常 都 是 从 BaseAppException 继 承 下 来 的 。 关 于 非 受 控 的 异常 BaseAppRuntimeException, 可 以 在 前 段 控 制 器 的 基 类 AbstractAction, 它 主 要负 责 日 志 的 记 录 , 页 面 的 跳 转 等 。异常处理框架的作用传 统 的 异 常 处 理 机 制 , 简 单 的 讲 是 通 过 了 一 个 前 段 控 制 器 加 上 设 计 良 好 的 异 常类 体 系 来 处 理 企 业 异 常 的 。 但 是 这 里 有 一 个 问 题 , 如 果 异 常 消 息 和 异 常 种 类 一 多 的 话 ,特 别 是 对 大 型 业 务 系 统 而 言 , 即 便 有 了 一 个 异 常 类 的 体 系 , 随 着 业 务 的 增 加 ,结