首先是exceptions包,主要包括ExceptionFactory
和RuntimeException的实现类。
如图所示,IbatisException继承自RuntimeException,而PersistenceException继承自IbatisException。框架中用到的其他Exception也主要继承自PersistenceException。
public class IbatisException extends RuntimeException {
private static final long serialVersionUID = 3880206998166270511L;
public IbatisException() {
super();
}
public IbatisException(String message) {
super(message);
}
public IbatisException(String message, Throwable cause) {
super(message, cause);
}
public IbatisException(Throwable cause) {
super(cause);
}
}
public class PersistenceException extends IbatisException {
private static final long serialVersionUID = -7537395265357977271L;
public PersistenceException() {
super();
}
public PersistenceException(String message) {
super(message);
}
public PersistenceException(String message, Throwable cause) {
super(message, cause);
}
public PersistenceException(Throwable cause) {
super(cause);
}
}
ExceptionFactory 是一个静态工厂,只有一个方法wrapException()
主要用来包装异常,将程序中的Exception包装成RuntimeException,配合事务的rollback。
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);
}
}
再来看异常上下文,这里用到了单例模式。
上下文中主要包括,异常的来源、原因、sql语句等.
private ErrorContext stored;
可以用来存储一个异常,供程序recall()
。
reset()
将当前异常信息置空。
toString()
被重写,用来打印异常信息。
public class ErrorContext {
private static final String LINE_SEPARATOR = System.getProperty("line.separator","\n");
private static final ThreadLocal<ErrorContext> LOCAL = new ThreadLocal<ErrorContext>();
private ErrorContext stored;
private String resource;
private String activity;
private String object;
private String message;
private String sql;
private Throwable cause;
private ErrorContext() {
}
public static ErrorContext instance() {
ErrorContext context = LOCAL.get();
if (context == null) {
context = new ErrorContext();
LOCAL.set(context);
}
return context;
}
public ErrorContext store() {
stored = this;
LOCAL.set(new ErrorContext());
return LOCAL.get();
}
public ErrorContext recall() {
if (stored != null) {
LOCAL.set(stored);
stored = null;
}
return LOCAL.get();
}
public ErrorContext resource(String resource) {
this.resource = resource;
return this;
}
public ErrorContext activity(String activity) {
this.activity = activity;
return this;
}
public ErrorContext object(String object) {
this.object = object;
return this;
}
public ErrorContext message(String message) {
this.message = message;
return this;
}
public ErrorContext sql(String sql) {
this.sql = sql;
return this;
}
public ErrorContext cause(Throwable cause) {
this.cause = cause;
return this;
}
public ErrorContext reset() {
resource = null;
activity = null;
object = null;
message = null;
sql = null;
cause = null;
LOCAL.remove();
return this;
}
@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();
}
}
具体代码调用
private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) {
Transaction tx = null;
try {
final Environment environment = configuration.getEnvironment();
final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment);
tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);
final Executor executor = configuration.newExecutor(tx, execType);
return new DefaultSqlSession(configuration, executor, autoCommit);
} catch (Exception e) {
closeTransaction(tx); // may have fetched a connection so lets call close()
throw ExceptionFactory.wrapException("Error opening session. Cause: " + e, e); //通过ExceptionFactory将Exception包装成RuntimeException
} finally {
ErrorContext.instance().reset(); //使用单例模式,因为在wrapException()中对ErrorContext中的成员变量等做了设置,所以在finally 中需要重置这些变量的引用。
}
}