1. 程式人生 > 其它 >Mybatis原始碼分析(2)

Mybatis原始碼分析(2)

Mybatis原始碼分析(2)

目錄

Mybatis原始碼分析(1)

接上一章總結【從哪裡開始?】

1、SqlSessionManager

實現至SqlSession

public class SqlSessionManager implements SqlSessionFactory, SqlSession {

  private final SqlSessionFactory sqlSessionFactory;
  private final SqlSession sqlSessionProxy;

  private final ThreadLocal<SqlSession> localSqlSession = new ThreadLocal<>();
}

程式碼中容易看到:SqlSessionManager管理器繼承自SqlSession,裡面維護了自己的一個SqlSessionFactory 和一個SqlSession的代理型別(原始碼可以看出是jdk代理模式)以及一個當前執行緒可見全域性的localSqlSession

public <T> T selectOne(String statement, Object parameter) {
  return sqlSessionProxy.selectOne(statement, parameter);
}

selectOne為例我們能看到這是通過代理來完成的sql查詢操作,那麼這個代理是做了什麼增強呢?

@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
  final SqlSession sqlSession = SqlSessionManager.this.localSqlSession.get();
  if (sqlSession != null) {
    try {
      return method.invoke(sqlSession, args);
    } catch (Throwable t) {
      throw ExceptionUtil.unwrapThrowable(t);
    }
  } else {
    try (SqlSession autoSqlSession = openSession()) {
      try {
        final Object result = method.invoke(autoSqlSession, args);
        autoSqlSession.commit();
        return result;
      } catch (Throwable t) {
        autoSqlSession.rollback();
        throw ExceptionUtil.unwrapThrowable(t);
      }
    }
  }
}

我們可以看到這個代理,為我們做了如下幾件事:

  • 獲取本地的SqlSession
  • 如果本地有,並執行方法且不加增強
  • 如果本地沒有,用當前管理器的工廠建立一個新的SqlSession並自動提交或回滾

2、DefaultSqlSession

同上,也實現至SqlSession

public class DefaultSqlSession implements SqlSession {

  private final Configuration configuration;// 配置資訊,也是生成Mapper代理類的方式
  private final Executor executor;// 內部封裝的執行器,用來真正執行操作

  private final boolean autoCommit;// 暫不解釋
  private boolean dirty;// 暫不解釋
  private List<Cursor<?>> cursorList;// 暫不解釋

  public DefaultSqlSession(Configuration configuration, Executor executor, boolean autoCommit) {
    this.configuration = configuration;
    this.executor = executor;
    this.dirty = false;
    this.autoCommit = autoCommit;
  }
}

3、Executor繼承結構圖(下章解釋)

Executor 是SqlSession底層真正執行操作的執行器

3、Mapper:對映器例項

對映器是一些繫結對映語句的介面。對映器介面的例項是從 SqlSession 中獲得的。雖然從技術層面上來講,任何對映器例項的最大作用域與請求它們的 SqlSession 相同。但方法作用域才是對映器例項的最合適的作用域。 也就是說,對映器例項應該在呼叫它們的方法中被獲取,使用完畢之後即可丟棄。 對映器例項並不需要被顯式地關閉。儘管在整個請求作用域保留對映器例項不會有什麼問題,但是你很快會發現,在這個作用域上管理太多像 SqlSession 的資源會讓你忙不過來。 因此,最好將對映器放在方法作用域內。就像下面的例子一樣:

try (SqlSession session = sqlSessionFactory.openSession()) {
  BlogMapper mapper = session.getMapper(BlogMapper.class);
  // 你的應用邏輯程式碼
}

4、SqlSession是如何生成Mapper例項的?

我們可以看出SqlSession是有兩個實現類,其實現類中都維護一個配置資訊例項,事實上不管是哪一個,最終都會走到Configuration的一個方法中:

public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
  return mapperRegistry.getMapper(type, sqlSession);
}

這裡我們是從MapperRegistry中獲取Mapper的

public class MapperRegistry {

  private final Configuration config;
  // 維護了一個類位元組碼與對應的Mapper的代理工廠快取
  private final Map<Class<?>, MapperProxyFactory<?>> knownMappers = new HashMap<>();

  public MapperRegistry(Configuration config) {
    this.config = config;
  }
}

MapperRegistry 中維護了一個代理型別工廠容器,此工廠應該用來建立相應的Mapper介面的代理類,我們往下依次推下去:

/**
1 ---------------------------------------------------------------------------------------------
*/
public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
  // 根據Mapper型別獲取Mapper代理工廠
  final MapperProxyFactory<T> mapperProxyFactory = (MapperProxyFactory<T>) knownMappers.get(type);
    // Mapper代理工廠建立例項
    return mapperProxyFactory.newInstance(sqlSession);
}
/**
2 -------------------------new MapperProxy例項用來建立代理類--------------------------------------
*/
 public T newInstance(SqlSession sqlSession) {
    final MapperProxy<T> mapperProxy = new MapperProxy<>(sqlSession, mapperInterface, methodCache);
    return newInstance(mapperProxy);
  }
/**
3 -----------------------mapperProxy實現了InvocationHandler-------------------------------------
*/
public class MapperProxy<T> implements InvocationHandler, Serializable {}
/**
4 -----------------------------動態代理生成Mapper代理類-------------------------------------------
*/
protected T newInstance(MapperProxy<T> mapperProxy) {
    return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[] { mapperInterface }, mapperProxy);
  }

我們發現其實底層是通過SqlSession下面的子類--> Configuration-->MapperRegistry-->MapperProxyFactory-->MapperProxy-->JDK 自帶的基於介面的動態代理這些步驟建立的Mapper例項