本篇聊一聊MyBatis
所用到的一些设计模式。
关于MyBatis一些实现原理,可以参考 MyBatis的Mapper机制
1.工场模式
关于工场模式的具体原理和实现可以参考 浅谈模式 - 工场模式
SqlSessionFactory
public interface SqlSessionFactory {
SqlSession openSession();
SqlSession openSession(boolean autoCommit);
SqlSession openSession(Connection connection);
SqlSession openSession(TransactionIsolationLevel level);
SqlSession openSession(ExecutorType execType);
SqlSession openSession(ExecutorType execType, boolean autoCommit);
SqlSession openSession(ExecutorType execType, TransactionIsolationLevel level);
SqlSession openSession(ExecutorType execType, Connection connection);
Configuration getConfiguration();
}
上面这部分没太多好解释的。
纯粹从设计模式角度讲,就是工场方法模式,构建单例维度的SqlSession
对象。
从MyBatis本身讲,用来打开会话,如果使用了mybatis-spring
,这部分是被屏蔽了的。参考文档 MyBatis-Spring的Mapper机制
MapperProxyFactory
public class MapperProxyFactory {
private final Class mapperInterface;
private final Map methodCache = new ConcurrentHashMap();
public MapperProxyFactory(Class mapperInterface) {
this.mapperInterface = mapperInterface;
}
public Class getMapperInterface() {
return mapperInterface;
}
public Map getMethodCache() {
return methodCache;
}
@SuppressWarnings("unchecked")
protected T newInstance(MapperProxy mapperProxy) {
return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[] { mapperInterface }, mapperProxy);
}
public T newInstance(SqlSession sqlSession) {
final MapperProxy mapperProxy = new MapperProxy(sqlSession, mapperInterface, methodCache);
return newInstance(mapperProxy);
}
}
实际使用了JDK
的动态代理,在调用newInstance
方法的时候会创建一个动态代理对象Mapper
对象。具体原理的讲解可以参考 MyBatis的Mapper机制
2.建造者模式
Environment.Builder
SqlSessionFactoryBuilder
建造者模式,原理和结构都比较简单,列出了MyBatis的实用点,具体的代码比较大,就不列了,自己查看即可。基本原理可以参考文档 浅谈模式 - 建造者模式
3.代理模式
关于工场模式的具体原理和实现可以参考 浅谈模式 - 代理模式
非Spring的情况
在调用sqlSession.getMapper
的时候,实时生成动态代理类(生命周期是这一次调用或者一个调用会话)。invoke
完成之后,调用sqlsession.close()
,看你有没有配置连接池,如果配置了connection
应该是被代理或者包装过了。内部实际不是真正的断开连接,而是放回池中。参考文档 MyBatis的Mapper机制
Mybatis-Spring的情况
加上spring
之后,又在Mapper
代理的基础上,做了SqlSession
的代理。关键类SqlSessionTemplate
。参考文档 MyBatis-Spring的Mapper机制
4.装饰器模式
SqlSessionTemplate
对SqlSession
的包装。属于装饰器模式。
public class SqlSessionTemplate implements SqlSession, DisposableBean {
// 包装了SqlSession的代理对象
private final SqlSession sqlSessionProxy;
// 省去了大量代码
// 动态代理类
private class SqlSessionInterceptor implements InvocationHandler {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
SqlSession sqlSession = getSqlSession(
SqlSessionTemplate.this.sqlSessionFactory,
SqlSessionTemplate.this.executorType,
SqlSessionTemplate.this.exceptionTranslator);
try {
Object result = method.invoke(sqlSession, args);
if (!isSqlSessionTransactional(sqlSession, SqlSessionTemplate.this.sqlSessionFactory)) {
// force commit even on non-dirty sessions because some databases require
// a commit/rollback before calling close()
sqlSession.commit(true);
}
return result;
} catch (Throwable t) {
Throwable unwrapped = unwrapThrowable(t);
if (SqlSessionTemplate.this.exceptionTranslator != null && unwrapped instanceof PersistenceException) {
// release the connection to avoid a deadlock if the translator is no loaded. See issue #22
closeSqlSession(sqlSession, SqlSessionTemplate.this.sqlSessionFactory);
sqlSession = null;
Throwable translated = SqlSessionTemplate.this.exceptionTranslator.translateExceptionIfPossible((PersistenceException) unwrapped);
if (translated != null) {
unwrapped = translated;
}
}
throw unwrapped;
} finally {
if (sqlSession != null) {
closeSqlSession(sqlSession, SqlSessionTemplate.this.sqlSessionFactory);
}
}
}
}
}
5.模板方法模式
BaseExecutor
。这是个抽象类,一般抽象类中看到下面这种抽象方法,就是用了模板方法模式
protected abstract int doUpdate(MappedStatement ms, Object parameter)
throws SQLException;
protected abstract List doFlushStatements(boolean isRollback)
throws SQLException;
protected abstract List doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql)
throws SQLException;
protected abstract Cursor doQueryCursor(MappedStatement ms, Object parameter, RowBounds rowBounds, BoundSql boundSql)
throws SQLException;
其他还有一些非核心的设计模式运用。比如:
PropertyTokenizer
,运用了迭代器模式。
ErrorContext
,运用了线程级别的单例模式。