您的位置:首页 > 其它

构建更好的异常处理框架

2004-11-15 14:56 477 查看
业应用程序在构建时常常对异常处理关注甚少,这会造成对低级异常(如
java.rmi.RemoteException
javax.naming.NamingException
)的过度依赖。在EJB最佳实践的这篇专栏文章中,BrettMcLaughlin解释了为什么对异常处理投入一点关注就会给我们带来很大的帮助,并向您展示了两种简单技术,它们将帮助您正确地构建更健壮且有用的异常处理框架。
在本系列先前的技巧文章中,异常处理不属于讨论的核心范围之内。但是,您可能会发现一点,那就是我们一直都回避来自Web层的低级异常。我们向客户机提供诸如
ApplicationException
InvalidDataException
之类的异常,而没有让Web层处理象
java.rmi.RemoteException
javax.naming.NamingException
这样的异常。
远程和命名异常是系统级异常,而应用程序和非法数据异常是业务级异常,因为它们提交更适用的业务信息。当决定抛出何种类型的异常时,您应该总是首先考虑将要处理所报告异常的层。Web层通常是由执行业务任务的最终用户驱动的,所以最好用它处理业务级异常。但是,在EJB层,您正在执行系统级任务,如使用JNDI或数据库。尽管这些任务最终将被合并到业务逻辑中,但是最好用诸如
RemoteException
之类的系统级异常来表示它们。
理论上,您可以让所有Web层方法预期处理和响应单个应用程序异常,正如我们在先前的一些示例中所做的一样。但这种方法不适用于长时间运行。让您的委派方法抛出更具体的异常,这是一个好得多的异常处理方案,从根本上讲,这对接收客户机更有用。在这篇技巧文章中,我们将讨论两种技术,它们将有助于您创建信息更丰富、更具体的异常,而不会生成大量不必要的代码。
嵌套的异常
在设计可靠的异常处理方案时,要考虑的第一件事情就是对所谓的低级系统级异常进行抽象化。这些核心Java异常通常会报告网络流量中的错误、JNDI或RMI问题,或者是应用程序中的其它技术问题。
RemoteException
EJBException
NamingException
是企业Java编程中低级异常的常见例子。
这些异常完全没有任何意义,由Web层的客户机接收时尤其容易混淆。如果客户机调用
purchase()
并接收到
NamingException
,那么它在解决这个异常时会一筹莫展。同时,应用程序代码可能需要访问这些异常中的信息,因此不能轻易地抛弃或忽略它们。
答案是提供一类更有用的异常,它还包含低级异常。清单1演示了一个专为这一点设计的简单
ApplicationException

清单1.嵌套的异常
packagecom.ibm;
importjava.io.PrintStream;
importjava.io.PrintWriter;
publicclassApplicationExceptionextendsException{
/**AwrappedThrowable*/
protectedThrowablecause;
publicApplicationException(){
super("Erroroccurredinapplication.");
}
publicApplicationException(Stringmessage){
super(message);
}
publicApplicationException(Stringmessage,Throwablecause){
super(message);
this.cause=cause;
}
//CreatedtomatchtheJDK1.4Throwablemethod.
publicThrowableinitCause(Throwablecause){
this.cause=cause;
returncause;
}
publicStringgetMessage(){
//Getthisexception'smessage.
Stringmsg=super.getMessage();
Throwableparent=this;
Throwablechild;
//Lookfornestedexceptions.
while((child=getNestedException(parent))!=null){
//Getthechild'smessage.
Stringmsg2=child.getMessage();
//Ifwefoundamessageforthechildexception,
//weappendit.
if(msg2!=null){
if(msg!=null){
msg+=":"+msg2;
}else{
msg=msg2;
}
}
//AnynestedApplicationExceptionwillappenditsown
//children,soweneedtobreakoutofhere.
if(childinstanceofApplicationException){
break;
}
parent=child;
}
//Returnthecompletedmessage.
returnmsg;
}
publicvoidprintStackTrace(){
//Printthestacktraceforthisexception.
super.printStackTrace();
Throwableparent=this;
Throwablechild;
//Printthestacktraceforeachnestedexception.
while((child=getNestedException(parent))!=null){
if(child!=null){
System.err.print("Causedby:");
child.printStackTrace();
if(childinstanceofApplicationException){
break;
}
parent=child;
}
}
}
publicvoidprintStackTrace(PrintStreams){
//Printthestacktraceforthisexception.
super.printStackTrace(s);
Throwableparent=this;
Throwablechild;
//Printthestacktraceforeachnestedexception.
while((child=getNestedException(parent))!=null){
if(child!=null){
s.print("Causedby:");
child.printStackTrace(s);
if(childinstanceofApplicationException){
break;
}
parent=child;
}
}
}
publicvoidprintStackTrace(PrintWriterw){
//Printthestacktraceforthisexception.
super.printStackTrace(w);
Throwableparent=this;
Throwablechild;
//Printthestacktraceforeachnestedexception.
while((child=getNestedException(parent))!=null){
if(child!=null){
w.print("Causedby:");
child.printStackTrace(w);
if(childinstanceofApplicationException){
break;
}
parent=child;
}
}
}
publicThrowablegetCause(){
returncause;
}
}
清单1中的代码很简单;我们已经简单地将多个异常“串”在一起,以创建单个、嵌套的异常。但是,真正的好处在于将这种技术作为出发点,以创建特定于应用程序的异常层次结构。异常层次结构将允许EJB客户机既接收特定于业务的异常也接收特定于系统的信息,而不需要编写大量额外代码。
异常层次结构
异常层次结构应该从一些十分健壮而又通用的异常入手,如
ApplicationException
。如果您将顶级异常搞得太具体,那么其结果是您今后将不得不重新构造层次结构,以适应某些较通用的情况。
因此,让我们假定您的应用程序要求
NoSuchBookException
InsufficientFundsException
SystemUnavailableException
。您不必创建这三个异常,让它们继承
ApplicationException
,然后只需提供极少几个必须的构造器来创建格式化的消息。清单2是此类异常层次结构的示例:
清单2.异常层次结构
packagecom.ibm.library;
importcom.ibm.ApplicationException;
publicclassNoSuchBookExceptionextendsApplicationException{
publicNoSuchBookException(StringbookName,StringlibraryName){
super("Thebook'"+bookName+"'wasnotfoundinthe'"+
libraryName+"'library.");
}
}
当需要编写大量专用异常时,异常层次结构极大地简化了工作。对于一个异常,为每个异常类添加一个或两个构造器,所花费时间很少不超过几分钟。您还经常需要给这些更具体的异常(这些异常也是主应用程序异常的子类)提供子类,以提供更具体的异常。例如,您可能需要
InvalidTitleException
BackorderedException
来继承
NoSuchBookException

企业应用程序在构建时通常都不会注意异常处理。尽管依靠低级异常(如
RemoteException
NamingException
)很容易(有时也很诱人),但如果一开始就建立一个可靠的、深思熟虑的异常模型,则您将在应用程序上少花很多精力。创建一个嵌套的、层次结构化的异常框架将改进代码的可读性及其可用性。
参考资料

查看BrettMcLaughlin撰写的完整的EJB最佳实践系列。

EnterpriseJavaBean基础”教程(developerWorks,2001年3月)是着手了解EJB技术的好途径。

EricAllen的诊断Java代码专栏是帮助您管理Java代码中常见错误的技巧文章“仓库”。

Java架构设计师SrikanthShenoy在其文章“EJB异常处理的最佳做法”(developerWorks,2002年5月)中演示了如何在基于EJB技术的系统上进行编码以更快地解决问题。

SunMicrosystems的EJB技术主页是了解关于EJB技术信息的良好起点。

另一个很棒的参考资料是TheServerSide.com,它提供了关于J2EE的文章和信息。

请参阅developerWorksJava技术教程页面,以获取关于EJB技术和J2EE的developerWorks免费教程清单。

developerWorksJava技术专区可以找到多达数百篇的Java技术参考资料。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: