MyBatis中的设计模式

本篇聊一聊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.装饰器模式

SqlSessionTemplateSqlSession的包装。属于装饰器模式。

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,运用了线程级别的单例模式。

你可能感兴趣的:(MyBatis中的设计模式)