读书人

处理错误的智慧

发布时间: 2012-12-22 12:05:05 作者: rapoo

处理异常的智慧

?

?

1. 忽略异常,往上抛

?

一般在打开Socket时出现的异常应该往上抛,不应该吃掉异常,致使上层的调用者无法感知这些异常。我们在Hadoop的RPC的Server初始化中可以看到这一点。如果在打开Socket的时候抛出异常,该异常一直往上抛,从而到达最顶端,即Namenode的初始化,从而导致Namenode初始化失败。因为RPC中Server的Socket是一个必不可少的组件,如果该组件初始化失败,会使服务不完整。所以,需要让上层调用者知道这个失败。

?

一般最底层处理IO的异常应该往上抛。例如在Hadoop的RPC的Server中的channelWrite(WriteableByteChannel channel, ByteBuffer buffer)中,channle的write方法产生的异常会往上抛,所以,channelWrite方法声明抛出IOException。我们可以看到,在最上层的处理逻辑中,会捕获IOException,做对应的一些业务处理:记录日志,或关闭这个客户端链接。

?

2. 将底层异常转换为业务异常

?

在Voldemort中,我们可以看到Voldemort会把底层的IOException转换为VolemortException。有意思的是,VoldemortException是一个RuntimeException,所以,Voldemort的代码看起来更加干净,清爽一些。

?

3. 异常可能影响后续的处理流程

?

下面是Hadoop的RPC的Server中的一段代码:

?

try {        count = c.readAndProcess();      } catch (InterruptedException ieo) {        LOG.info(getName() + ": readAndProcess caught InterruptedException", ieo);        throw ieo;      } catch (Exception e) {        LOG.info(getName() + ": readAndProcess threw exception " + e + ". Count of bytes read: " + count, e);        count = -1; //so that the (count < 0) block is executed      }      if (count < 0) {        if (LOG.isDebugEnabled())          LOG.debug(getName() + ": disconnecting client " +                     c.getHostAddress() + ". Number of active connections: "+                    numConnections);        closeConnection(c);        c = null;      }
?

我们可以看到readAndProcess方法抛出的除了InterruptedException以外的其他异常被捕获到(当然包括IOExcetion),在记录异常的同时,设置count=-1,标识这次读写处理失败。在后面的逻辑中,如果count小于0,说明这个链接已经被损坏,需要调用closeException方法关闭这个链接。

?

4. 特定的异常需要被特别照顾

?

在上面的代码中,InterruptedException被特别捕获,并被抛出。在上层,该异常只是被记录下来,所以,该异常并不会引起链接的关闭。

?

?

?

读书人网 >编程

热点推荐