Mybatis原始碼分析(2)
Mybatis原始碼分析(2)
目錄接上一章總結【從哪裡開始?】
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例項