站内搜索: 请输入搜索关键词

当前页面: 开发资料首页Java 专题一个用于J2EE应用程序的异常处理框架_软件_Java

一个用于J2EE应用程序的异常处理框架_软件_Java

摘要: 本文将使用Struts框架作为表示实现,但该方法适用于任何表示实现。
  在大多数Java项目中,大部分代码都是样板代码。异常处理就属于此类代码。即使业务逻辑只有3到4行代码,用于异常处理的代码也要占10到20行。本文将讨论如何让异常处理保持简单和直观,使开发人员可以专心于开发业务逻辑,而不是把时间浪费在编写异常处理的样板代码上。本文还将说明用于在J2EE环境中创建和处理异常的基础知识和指导原则,并提出了一些可以使用异常解决的业务问题。本文将使用Struts框架作为表示实现,但该方法适用于任何表示实现。

  使用checked和unchecked异常的场景

  您是否曾经想过,为什么要在编写好的代码块周围放置一个try-catch块,即便明知道无法对这些异常进行什么处理,而只满足于把它们放在catch块中?您可能想知道,为什么不能把这项工作放在一个集中的地方完成?在大多数情况下,这个地方对于J2EE应用程序来说就是一个前端控制器。换句话说,开发人员不会因为它们而受到干扰,因为根本不必很多地过问它们。但是,如果一个方法名称包含一个throws子句,会出现什么情况呢?开发人员或者必须捕捉这些异常,或者把它们放在自己的方法的throws子句中。这就是痛苦的根源!幸运的是,Java API有一类叫做unchecked exception的异常,它们不必捕捉。但是,仍然存在一个问题:根据什么来决定哪些是checked异常,哪些是unchecked异常?下面给出一些指导原则:

  终端用户无法采取有效操作的异常应该作为unchecked异常。例如,致命的和不可恢复的异常就应该是unchecked。把XMLParseException(在解析XML文件时抛出)作为checked异常没有任何意义,因为惟一能够采取的措施就是基于异常跟踪来解决根本问题。通过扩展java.lang.RuntimeException,可以创建自定义的unchecked异常。

  在应用程序中,与用户操作相关的异常应该是checked异常。checked异常要求客户端来捕捉它们。您可能会问,为什么不把所有异常都当作是unchecked。这样做的问题在于,其中一些异常无法在正确的位置被捕捉到。这会带来更大的问题,因为错误只有在运行时才能被识别。checked异常的例子有业务确认异常、安全性异常等等。

  异常抛出策略

  只捕捉基本应用程序异常(假定为BaseAppException)并在throws子句中声明

  在大多数J2EE应用程序中,关于针对某个异常应该在哪一界面上显示哪条错误消息的决策只能在表示层中做出。这会带来另一个问题:为什么我们不能把这种决策放在一个公共的地方呢?在J2EE应用程序中,前端控制 器就是一个进行常见处理的集中位置。

  此外,必须有一种用于传播异常的通用机制。异常也需要以一种普适的方式得到处理。为此,我们始终需要在控制器端捕捉基本应用程序异常BaseAppException。这意味着我们需要把BaseAppException异常(只有这个异常)放入可以抛出checked异常的每个方法的throws子句中。这里的概念是使用多态来隐藏异常的实际实现。我们在控制器中捕捉BaseAppException,但是所抛出的特定异常实例可能是几个派生异常类中的任意一个。借助于这种方法,可以获得许多异常处理方面的灵活性:

  不需要在throws子句中放入大量的checked异常。throws子句中只需要有一个异常。

  不需要再对应用程序异常使用混乱的catch块。如果需要处理它们,一个catch块(用于BaseAppException)就足够了。

  开发人员不需要亲自进行异常处理(日志记录以及获取错误代码)。这种抽象是由ExceptionHandler完成的,稍后本文会就此点进行讨论。

  即使稍后把更多异常引入到方法实现中,方法名称也不会改变,因此也不需要修改客户端代码,否则就会引起连锁反应。然而,抛出的异常需要在方法的Javadoc中指定,以便让客户端可以看到方法约束。

  下面给出抛出checked异常的一个例子:

<table borderColor=#cccccc width="90%" align=center bgColor=#e1e1e1 border=1> <tr> <td>public void updateUser(UserDTO userDTO)
throws BaseAppException{
 UserDAO userDAO = new UserDAO();
 UserDAO.updateUser(userDTO);
 ...
 if(...)
 throw new RegionNotActiveException("Selected region is not active");
}

Controller Method:
...
try{
 User user = new User();
 user.updateUser(userDTO);
}catch(BaseAppException ex){
 //ExceptionHandler is used to handle
 //all exceptions derived from BaseAppException
}
...</td></tr></table>
  迄今为止,我们已经说明,对于所有可能抛出checked异常并被Controller调用的方法,其throws子句中应该只包含checked异常。然而,这实际上暗示着我们在throws子句中不能包含其他任何应用程序异常。但是,如果需要基于catch块中某种类型的异常来执行业务逻辑,那又该怎么办呢?要处理这类情况,方法还可以抛出一个特定异常。记住,这是一种特例,开发人员绝对不能认为这是理所当然的。同样,此处讨论的应用程序异常应该扩展BaseAppException类。下面给出一个例子:

<table borderColor=#cccccc width="90%" align=center bgColor=#e1e1e1 border=1> <tr> <td>CustomerDAO method:
//throws CustomerNotActiveException along with
//BaseAppException
public CustomerDTO getCustomer(InputDTO inputDTO)
throws BaseAppException,
CustomerNotActiveException {
 . . .
 //Make a DB call to fetch the customer
 //details based on inputDTO
 . . .
 // if not details found
 throw new CustomerNotActiveException("Customer is not active");
}

Client method:

//catch CustomerNotActiveException
//and continues its processing
public CustomerDTO getCustomerDetails(UserDTO userDTO)
throws BaseAppException{
 ...
 CustomerDTO custDTO = null;
 try{
  //Get customer details
  //from local database
  customerDAO.getCustomerFromLocalDB();
 }catch(CustomerNotActiveException){
  ...
  return customerDAO .activateCustomerDetails();
 }
}</td></tr></table>

↑返回目录
前一篇: j2EE基础概念
后一篇: 对企业级Java应用程序及其部署进行建模