首页 | 新闻 | 新品 | 文库 | 方案 | 视频 | 下载 | 商城 | 开发板 | 数据中心 | 座谈新版 | 培训 | 工具 | 博客 | 论坛 | 百科 | GEC | 活动 | 主题月 | 电子展
返回列表 回复 发帖

EJB 异常处理的最佳做法(7)Web 层的 EJB 异常处理

EJB 异常处理的最佳做法(7)Web 层的 EJB 异常处理

Web 层的 EJB 异常处理在 Web 层设计中,把异常记录机制放到客户机端往往更容易也更高效。要能做到这一点,Web 层就必须是 EJB 层的唯一客户机。此外,Web 层必须建立在以下模式或框架之一的基础上:
  • 模式:业务委派(Business Delegate)、FrontController 或拦截过滤器(Intercepting Filter)
  • 框架:Struts 或任何包含层次结构的类似于 MVC 框架的框架
为什么异常记录应该在客户机端上发生呢?嗯,首先,控制尚未传到应用程序服务器之外。所谓的客户机层在 J2EE 应用程序服务器本身上运行,它由 JSP 页、servlet 或它们的助手类组成。其次,在设计良好的 Web 层中的类有一个层次结构(例如:在业务委派(Business Delegate)类、拦截过滤器(Intercepting Filter)类、http 请求处理程序(http request handler)类和 JSP 基类(JSP base class)中,或者在 Struts Action 类中),或者 FrontController servlet 形式的单点调用。这些层次结构的基类或者 Controller 类中的中央点可能包含有异常记录代码。对于基于会话 EJB 记录的情况,EJB 组件中的每一个方法都必须具有记录代码。随着业务逻辑的增加,会话 EJB 方法的数量也会增加,记录代码的数量也会增加。Web 层系统将需要更少的记录代码。如果您的 Web 层和 EJB 层在同一地方并且不需要支持任何其它类型的客户机,那么您应该考虑这一备用方案。不管怎样,记录机制不会改变;您可以使用与前面的部分所描述的相同技术。
真实世界的复杂性到现在为止,您已经看到了简单情形的会话和实体 EJB 组件的异常处理技术。然而,应用程序异常的某些组合可能会更令人费解,并且有多种解释。清单 9 显示了一个示例。         OrderEJB 的         ejbCreate() 方法试图获取         CustomerEJB 的一个远程引用,这会导致         FinderException 。         OrderEJB 和         CustomerEJB 都是实体 EJB 组件。您应该如何解释         ejbCreate() 中的这个         FinderException 呢?是把它当作应用程序异常对待呢(因为 EJB 规范把它定义为标准应用程序异常),还是当作系统异常对待?      
清单 9. ejbCreate() 方法中的 FinderException
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public Object ejbCreate(OrderValue val) throws CreateException {
     try {
        if (value.getItemName() == null) {
          throw new CreateException("Cannot create Order without a name");
        }
        String custId = val.getCustomerId();
        Customer cust = customerHome.fingByPrimaryKey(custId);
        this.customer = cust;
     } catch (FinderException ne) {
          //How do you handle this Exception ?
     } catch (RemoteException re) {
      //This is clearly a System Exception
      throw ExceptionLogUtil.createLoggableEJBException(re);
     }
     return null;
}




虽然没有什么东西阻止您把         FinderException 当应用程序异常对待,但把它当系统异常对待会更好。原因是:EJB 客户机倾向于把 EJB 组件当黑箱对待。如果         createOrder() 方法的调用者获得了一个         FinderException ,这对调用者并没有任何意义。         OrderEJB 正试图设置客户远程引用这件事对调用者来说是透明的。从客户机的角度看,失败仅仅意味着该订单无法创建。      
这类情形的另一个示例是,会话 EJB 组件试图创建另一个会话 EJB,因而导致了一个         CreateException 。一种类似的情形是,实体 EJB 方法试图创建一个会话 EJB 组件,因而导致了一个         CreateException 。这两个异常都应该当作系统异常对待。      
另一个可能碰到的挑战是会话 EJB 组件在它的某个容器回调方法中获得了一个         FinderException 。您必须逐例处理这类情况。您可能要决定是把         FinderException 当应用程序异常还是系统异常对待。请考虑清单 1 的情况,其中调用者调用了会话 EJB 组件的         deleteOldOrder 方法。如果我们不是捕获         FinderException ,而是将它抛出,会怎么样呢?在这一特定情况中,把         FinderException 当系统异常对待似乎是符合逻辑的。这里的理由是,会话 EJB 组件倾向于在它们的方法中做许多工作,因为它们处理工作流情形,并且它们对调用者而言是黑箱。      
另一方面,请考虑会话 EJB 正在处理下订单的情形。要下一个订单,用户必须有一个简档 ― 但这个特定用户却还没有。业务逻辑可能希望会话 EJB 显式地通知用户她的简档丢失了。丢失的简档很可能表现为会话 EJB 组件中的         javax.ejb.ObjectNotFoundException (         FinderException 的一个子类)。在这种情况下,最好的办法是在会话 EJB 组件中捕获         ObjectNotFoundException 并抛出一个应用程序异常,让用户知道她的简档丢失了。      
即使是有了很好的异常处理策略,另一个问题还是经常会在测试中出现,而且在产品中也更加重要。编译器和运行时优化会改变一个类的整体结构,这会限制您使用堆栈跟踪实用程序来跟踪异常的能力。这就是您需要代码重构的帮助的地方。您应该把大的方法调用分割为更小的、更易于管理的块。而且,只要有可能,异常类型需要多少就划分为多少;每次您捕获一个异常,都应该捕获已规定好类型的异常,而不是捕获所有类型的异常。
返回列表