天天看点

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<T> {

  private final Class<T> mapperInterface;
  private final Map<Method, MapperMethod> methodCache = new ConcurrentHashMap<Method, MapperMethod>();

  public MapperProxyFactory(Class<T> mapperInterface) {
    this.mapperInterface = mapperInterface;
  }

  public Class<T> getMapperInterface() {
    return mapperInterface;
  }

  public Map<Method, MapperMethod> getMethodCache() {
    return methodCache;
  }

  @SuppressWarnings("unchecked")
  protected T newInstance(MapperProxy<T> mapperProxy) {
    return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[] { mapperInterface }, mapperProxy);
  }

  public T newInstance(SqlSession sqlSession) {
    final MapperProxy<T> mapperProxy = new MapperProxy<T>(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<BatchResult> doFlushStatements(boolean isRollback)
    throws SQLException;

protected abstract <E> List<E> doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql)
    throws SQLException;

protected abstract <E> Cursor<E> doQueryCursor(MappedStatement ms, Object parameter, RowBounds rowBounds, BoundSql boundSql)
    throws SQLException;
           

其他还有一些非核心的设计模式运用。比如:

PropertyTokenizer

,运用了迭代器模式。

ErrorContext

,运用了线程级别的单例模式。