论坛首页 Java企业应用论坛

EJB3拦截器的异常处理

浏览 2510 次
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
作者 正文
   发表时间:2009-04-26  
拦截器的异常处理简单而有力.因为拦截器在组件方法的Java调用栈或回调被调用,你可以放置一个try/catch/finally块在InvocationContext.proceed( )方法的周围.你可以中断调用在它到达实际组件方法之前通过抛出一个异常在@AroundInvoke 或回调方法.你也可以允许捕获一个组件方法抛出异常和抛出一个不同的异常,或禁止异常.关于@AroundInvoke 拦截器,你甚至被允许重试组件方法调用在从组件方法捕获一个异常后.让我们看一些例子.
终止一个方法调用
参数确认是检查见到的业务方法的参数在以方法的逻辑着手进行有效值确认的业务逻辑.ProcessPayment EJB的byCheck()方法,使用确认来确定是否CheckDO参数有一个最小的检查值.也许我们卖我们的泰坦巡航系统软件作为一个ERP系统到不同的巡航公司到世办各地.我们可能想要关闭检查确认为我们的ProcessPayment EJB的一个部署.为其它的部署,我们增加更复杂的验证,如,检查一个和数库中的名字和支票帐号不符的帐户.拦截器给我们装载验证逻辑的能力,在拦截器类中与配置应用它作为需要到ProcessPayment EJB的不同部署中.
因为拦截器类允许你终止EJB方法的调用在拦截器类自身中,在实际到达的组件方法之前,这种方式使得模块化验证成为可能:
package com.titan.interceptors;

import javax.ejb.*;
import javax.annotation.*;
import javax.interceptor.*;

public class CheckValidation
{
   @Resource int minimumCheckNumber;
   @AroundInvoke
   public Object validateCheck(InvocationContext ctx) throws Exception {
      CheckDO
check = ctx.getParameters( )[1];
      if (check.checkNumber < minimumCheckNumber) {
         throw new PaymentException
("Check number is too low");
      }
      return ctx.proceed( );
   }
}
CheckValidation类中包装了ProcessPaymentBean.byCheck( )方法中的验证逻辑.它使用InvocationContext.getParameters( )方法来获取CheckDO参数.最小的检查从一个<env-entry>中的注入到拦截器类的minimumCheckNumber变量.validateCheck( )方法验证检查CheckDO中的数值大于最小的检查数值.如果验证失败它会终止调用同时抛出PaymentException.
验证仅仅是一个你想要终止EJB调用使用@AroundInvoke的方法.另一个例子是你实现自定义安全框架的情况下.EJB安全是很漂亮的基础,而且有时你有很大的安全需要.举例来说,你可能想要集成规则引挚到你的EJB中分析使用者作为方法和参数来确定是否允许使用者调用方法.这也可以使用一个拦截器来做.

捕获和重新抛出异常
除了终止一个给定的方法调用,你也可以捕获组件中使用被拦截器@AroundInvoke 方法抛出的异常.例如,你可以使用拦截器类作为一个抽像机制来创建异常处理框架.考虑到JDBC和java.sql.SQLException.当一个SQLException在你的程序代码中被抛出,不知道异常发生的原因,没有查看错误数或异常消息.不幸的是,不同的数据库提供商的错误代码和消息有所不同,因此,如果你想要处理确定情况的异常在确定的方法中,你的代码可以轻便的在不同数据库厂商之间.
让我们看两种常见的SQLException发生情况:死锁和游标无效.首先,我们将创建具体的异常继承SQLException:
@ApplicationException(rollback=true)
public class DatabaseDeadlockException extends java.sql.SQLException {
   public DatabaseDeadlockException(Exception cause) {
      Super(cause);
   }
}
@ApplicationException(rollback=true)
public class DatabaseCursorNotAvailable extends java.sql.SQLException {
   public DatabaseCursorNotAvailable(Exception cause) {
      super(cause);
   }
}
由于这些异常,我们依赖这些错误数来确定实际发生的数据库错误.客户端代码使用这些异常轻便的方式并且不用关心底层数据库提供商.但是在我们使用这些异常前,我们需要写拦截器类的异常处理:
public class MySQLExceptionHandler {
   @AroundInvoke
   public Object handleException(InvocationContext ctx) Exception {
      try {
         return ctx.proceed( );
   } catch (SQLException sql) {
       int ernum = sql.getErrorCode( );
       switch(ernum) {
       case 32343:
          throw new DatabaseDeadlockException(sql);
       case 22211:
          throw new DatabaseCursorNotAvailable(sql);
       ...
       default:
          throw new RollbackAlwaysOnException(sql);
       }
   }
}
@AroundInvoke方简单捕获任何SQLException被组件方法抛出的,并且转换它到一个适当的客户端代码可以捕获的异常类型.当然,有一个异常处理拦截器类对于每个数据库提供商.这里的代码是你的应用程序如果利用拦截器的行为:
// application client code
{
   try {
      ejbref.invokeSomeDatabaseOperation( );
   } catch (DatabaseDeadlockException deadlock) {
      // handle this specific error case in a special way
   }
}
所以,组合异常处理拦截器同EJB调用允许你有指定的代码来处理指定数据库的错误像死锁,不需要任何担心你的代码在厂商之间.
论坛首页 Java企业应用版

跳转论坛:
Global site tag (gtag.js) - Google Analytics