mybatis將所有的異常全部包成了運行時異常,減少在高層代碼中頻繁的try-catch導致的代碼臃腫問題。Persistence是它們共有的父類,繼承自RuntimeException非檢查型異常。IbatisException已經被棄用,每個異常類包裝了它們對應的組件的異常信息,根據異常的類型和message我們很容易的可以定位到異常,並獲取有用的幫助信息。
另外一部分則是這個異常包裝器
Mybatis暴露的API接口(SessionBuilder,Session操作)都用這個包裝器將所有的異常包裝成一個PersistenceException
public class ExceptionFactory { private ExceptionFactory() { // Prevent Instantiation } public static RuntimeException wrapException(String message, Exception e) { return new PersistenceException(ErrorContext.instance().message(message).cause(e).toString(), e); } }
異常的message來自 ErrorContext類,它是異常信息的上線文,提供了線程內的異常信息的通信和組裝,系統中的其他組件可以隨時隨地的將當時可能的異常上下文加入到這個ErrorContext中
ErrorContext最重要的設計是LOCAL成員,他是個ThreadLocal對象,隔離線程間的數據,所以這個異常上下文對象是線程私有的
ErrorContext還提供了異常信息的格式化打印工作
@Override public String toString() { StringBuilder description = new StringBuilder(); // message if (this.message != null) { description.append(LINE_SEPARATOR); description.append("### "); description.append(this.message); } // resource if (resource != null) { description.append(LINE_SEPARATOR); description.append("### The error may exist in "); description.append(resource); } // object if (object != null) { description.append(LINE_SEPARATOR); description.append("### The error may involve "); description.append(object); } // activity if (activity != null) { description.append(LINE_SEPARATOR); description.append("### The error occurred while "); description.append(activity); } // activity if (sql != null) { description.append(LINE_SEPARATOR); description.append("### SQL: "); description.append(sql.replace('\n', ' ').replace('\r', ' ').replace('\t', ' ').trim()); } // cause if (cause != null) { description.append(LINE_SEPARATOR); description.append("### Cause: "); description.append(cause.toString()); } return description.toString(); }