Mybatis 源码探究 (3)创建 SqlSessionFactory对象 执行sqlSession.getMapper()方法
Mybatis 源碼探究 (3)創建 SqlSessionFactory對象
時隔許久,終于又能接著來搞他啦。Mybatis 一起來探究吧。
先笑會再進入主題吧
開始啦
一、new SqlSessionFactoryBuilder().build(inputStream) 方法
String resource="mybatis-config.xml"; InputStream inputStream = Resources.getResourceAsStream(resource); SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(inputStream); public SqlSessionFactory build(InputStream inputStream) {//在這里又接著調用了重載方法build 我們接著往下走啊 return build(inputStream, null, null); }二、SqlSessionFactory build(InputStream inputStream, String environment, Properties properties) 方法
public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties) {try {//XMLConfigBuilder是對mybatis的配置文件進行解析的類,會對myabtis解析后的信息存放在Configuration對象中XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties);// 下面這句到重點啦return build(parser.parse());} catch (Exception e) {throw ExceptionFactory.wrapException("Error building SqlSession.", e);} finally {ErrorContext.instance().reset();try {inputStream.close();} catch (IOException e) {// Intentionally ignore. Prefer previous error.}} }一個一個講啊,慢慢來。
1、 new XMLConfigBuilder(inputStream, environment, properties);
XMLConfigBuilder : 翻譯過來就是XML配置器
XMLConfigBuilder是對mybatis的配置文件進行解析的類,會對myabtis解析后的信息存放在Configuration對象中,Configuration對象
會貫穿整個mybatis的執行流程,為mybatis的執行過程提供各種需要的配置信息。
public XMLConfigBuilder(InputStream inputStream, String environment, Properties props) {this(new XPathParser(inputStream, true, props, new XMLMapperEntityResolver()), environment, props); }XPathParser 和 XMLMapperEntityResolver 不是主要研究對象,我放在了文章最后,好奇的話,可以先滑到文末去看。
三、build(parser.parse()) 方法
先看parser.parse()方法 它的返回對象是核心配置對象Configuration
public Configuration parse() {if (parsed) {throw new BuilderException("Each XMLConfigBuilder can only be used once.");}parsed = true;parseConfiguration(parser.evalNode("/configuration"));return configuration; }進入到parseConfiguration(parser.evalNode("/configuration"))方法
可以看到 在這里就是將我們配置的好的文件 一步一步解析封裝到Configuration對象去。
private void parseConfiguration(XNode root) {try {// issue #117 read properties firstpropertiesElement(root.evalNode("properties"));Properties settings = settingsAsProperties(root.evalNode("settings"));loadCustomVfs(settings);loadCustomLogImpl(settings);typeAliasesElement(root.evalNode("typeAliases"));pluginElement(root.evalNode("plugins"));objectFactoryElement(root.evalNode("objectFactory"));objectWrapperFactoryElement(root.evalNode("objectWrapperFactory"));reflectorFactoryElement(root.evalNode("reflectorFactory"));settingsElement(settings);// read it after objectFactory and objectWrapperFactory issue #631environmentsElement(root.evalNode("environments"));databaseIdProviderElement(root.evalNode("databaseIdProvider"));typeHandlerElement(root.evalNode("typeHandlers"));mapperElement(root.evalNode("mappers"));} catch (Exception e) {throw new BuilderException("Error parsing SQL Mapper Configuration. Cause: " + e, e);}}這一段代碼主要作用就是將所有的配置文件加載到給定的對象。
我對于研究這個非常不熟練,結果就是走不出來。
mapperElement(root.evalNode("mappers"))里面要研究的東西不少,先略過哈。
四、return build(parser.parse()); 回到我們的入口處
我們可以知道 parser.parse() 構建出了一個 Configuration 對象,并成為了build()方法的入參。
這個build(parser.parse()); 是
public SqlSessionFactory build(Configuration config) {return new DefaultSqlSessionFactory(config);}這個地方就是將之前已經賦值好的Configuration 放在里面
public DefaultSqlSessionFactory(Configuration configuration) {this.configuration = configuration;}課間休息
地點:長沙
五、SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
至此 我們獲得了 SqlSessionFactory 對象,我們可以通過這獲取到mybatis操作數據庫的 SqlSession 對象。
SqlSession sqlSession = sessionFactory.openSession();openSession() 是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(); }我們這里調用的方法是這個哈
@Overridepublic SqlSession openSession() {// openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) return openSessionFromDataSource(configuration.getDefaultExecutorType(), null, false);}最后一個參數就是是否提交,如果不為true,我們做了修改or刪除,數據庫并不會修改or刪除。
接著往下看:
private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) {Transaction tx = null;try {final Environment environment = configuration.getEnvironment();final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment);tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);final Executor executor = configuration.newExecutor(tx, execType);return new DefaultSqlSession(configuration, executor, autoCommit);} catch (Exception e) {closeTransaction(tx); // may have fetched a connection so lets call close()throw ExceptionFactory.wrapException("Error opening session. Cause: " + e, e);} finally {ErrorContext.instance().reset();}}最后返回mybatis操作數據庫的 SqlSession 對象。
六、MyUserMapper mapper = sqlSession.getMapper(MyUserMapper.class);
/**檢索映射器。參數:type – 映射器接口類類型參數:<T> – 映射器類型返回:綁定到此 SqlSession 的映射器*/<T> T getMapper(Class<T> type);接下來開始套娃哈
我們實際調用的是它的實現類里的方法:
@Override public <T> T getMapper(Class<T> type) {return configuration.getMapper(type, this); }你看又牽扯到configuration對象了哈,知道它多重要了吧。
public <T> T getMapper(Class<T> type, SqlSession sqlSession) {return mapperRegistry.getMapper(type, sqlSession); }到了mapperRegistry 這個對象拉。 mapperRegistry的翻譯就是映射器注冊表 這個地方我目前還沒有搞懂它是什么時候注冊進去的哈。
public <T> T getMapper(Class<T> type, SqlSession sqlSession) {// 這里是去獲得 我們傳過來的 MyUserMapper.class的代理類的final MapperProxyFactory<T> mapperProxyFactory = (MapperProxyFactory<T>) knownMappers.get(type);if (mapperProxyFactory == null) {throw new BindingException("Type " + type + " is not known to the MapperRegistry.");}try {return mapperProxyFactory.newInstance(sqlSession);} catch (Exception e) {throw new BindingException("Error getting mapper instance. Cause: " + e, e);}}接下來繼續看這個 mapperProxyFactory.newInstance(sqlSession) 方法
public T newInstance(SqlSession sqlSession) {final MapperProxy<T> mapperProxy = new MapperProxy<>(sqlSession, mapperInterface, methodCache);return newInstance(mapperProxy);}接著套丫
protected T newInstance(MapperProxy<T> mapperProxy) {return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[] { mapperInterface }, mapperProxy);}當我們看到這里的時候就知道mybatis是通過反射和代理來進行這些操作的哈。
真實執行對象并不在,而是在 MapperProxy mapperProxy Mapper的代理對象中。
那個具體執行的,等下一篇博客哈。我還有很多沒懂的。
七、XPathParser
public class XPathParser {private final Document document;private boolean validation;private EntityResolver entityResolver;private Properties variables;private XPath xpath; }-
Document(Document對象)
Document 對象代表整個 XML 文檔,是一棵文檔樹的根,可為我們提供對文檔數據的最初(或最頂層)的訪問入口。
-
validation(是否開啟驗證標記)
該標記表示設置解析器在解析文檔的時候是否校驗文檔,在創建DocumentBuilderFactory實例對象時進行設置。
-
EntityResolver (加載本地的DTD文件
如果解析mybatis-config.xml 配置文件,默認聯網加載http://mybatis.org/dtd/mybatis-3- config.dtd 這個DTD 文檔,當網絡比較慢時會導致驗證過程緩慢。在實踐中往往會提前設置EntityResolver 接口對象加載本地的DTD 文件,從而避免聯網加載DTD文件。
-
XPath (XPath對象)
XPath 是一種為查詢XML 文檔而設計的語言,它可以與DOM 解析方式配合使用,實現對XML 文檔的解析。
-
variables(配置參數集合)。
對應配置文件中節點下定義的鍵值對集合,包括通過url或者resource讀取的鍵值對集合。
八、XMLMapperEntityResolver
對這個我沒有深究。doc注釋就是這么一句話:MyBatis DTD 的離線實體解析器 說實話DTD都是我第一次見 🤦?
當然百度是強大的。
它是EntityResolver子類,xml 的解析會基于事件觸發對應的 Resolver 或 Handler,當解析到 dtd 等外部資源時會
EntityResolver的resolveEntity方法。在XMLMapperEntityResolver.resolveEntity中,當解析到 mybatis-3-config.dtd、
mybatis-3-mapper.dtd 等資源時,會直接從 classpath 下的 org/apache/ibatis/builder/xml/ 路徑獲取資源,而不需要通過 url 獲取。
九、XMLMapperBuilder類
涉及到的類包括:
MapperBuilderAssistant:Mapper文件解析輔助類,包括了解析各種節點的方法。
BaseBuilder:XMLMapperBuilder與MapperBuilderAssistant的父類,保存了Configuration、TypeAliasRegistry、TypeHandlerRegistry三個屬性。
TypeAliasRegistry:別名對應關系,保存了字符串與類的對應信息,例如“String”字符串對應 String.class
TypeHandlerRegistry:注冊java.lang與java.sql類型對應關系
Configuration:Mapper文件解析節點完成后,存儲解析后的屬性信息。
XMLStatementBuilder:解析SQL語句節點類,解析后存儲在Configuration下的mappedStatements屬性
XMLMapperBuilder用于解析Mapper文件,包括namespace、parameterMap、resultMap以及各種SQL(insert/uppdate/delete/select)
解析過程中主要是parse()方法,
解析Mapper文件后會存儲在MapperBuilderAssistant以及它父類BaseBuilder的實例下,主要是Configuration類
自言自語
我這算是自己的閱讀筆記哈,無聊讀著看看。
算是我第一次讀源碼的記錄。
大家一起加油哦。
總結
以上是生活随笔為你收集整理的Mybatis 源码探究 (3)创建 SqlSessionFactory对象 执行sqlSession.getMapper()方法的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Error creating bean
- 下一篇: Mybatis 源码探究 (4) 将sq