Mybatis 源码探究 (3)创建 SqlSessionFactory对象 执行sqlSession.getMapper()方法
Mybatis 源碼探究 (3)創(chuàng)建 SqlSessionFactory對(duì)象
時(shí)隔許久,終于又能接著來搞他啦。Mybatis 一起來探究吧。
先笑會(huì)再進(jìn)入主題吧
開始啦
一、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) {//在這里又接著調(diào)用了重載方法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是對(duì)mybatis的配置文件進(jìn)行解析的類,會(huì)對(duì)myabtis解析后的信息存放在Configuration對(duì)象中XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties);// 下面這句到重點(diǎn)啦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.}} }一個(gè)一個(gè)講啊,慢慢來。
1、 new XMLConfigBuilder(inputStream, environment, properties);
XMLConfigBuilder : 翻譯過來就是XML配置器
XMLConfigBuilder是對(duì)mybatis的配置文件進(jìn)行解析的類,會(huì)對(duì)myabtis解析后的信息存放在Configuration對(duì)象中,Configuration對(duì)象
會(huì)貫穿整個(gè)mybatis的執(zhí)行流程,為mybatis的執(zhí)行過程提供各種需要的配置信息。
public XMLConfigBuilder(InputStream inputStream, String environment, Properties props) {this(new XPathParser(inputStream, true, props, new XMLMapperEntityResolver()), environment, props); }XPathParser 和 XMLMapperEntityResolver 不是主要研究對(duì)象,我放在了文章最后,好奇的話,可以先滑到文末去看。
三、build(parser.parse()) 方法
先看parser.parse()方法 它的返回對(duì)象是核心配置對(duì)象Configuration
public Configuration parse() {if (parsed) {throw new BuilderException("Each XMLConfigBuilder can only be used once.");}parsed = true;parseConfiguration(parser.evalNode("/configuration"));return configuration; }進(jìn)入到parseConfiguration(parser.evalNode("/configuration"))方法
可以看到 在這里就是將我們配置的好的文件 一步一步解析封裝到Configuration對(duì)象去。
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);}}這一段代碼主要作用就是將所有的配置文件加載到給定的對(duì)象。
我對(duì)于研究這個(gè)非常不熟練,結(jié)果就是走不出來。
mapperElement(root.evalNode("mappers"))里面要研究的東西不少,先略過哈。
四、return build(parser.parse()); 回到我們的入口處
我們可以知道 parser.parse() 構(gòu)建出了一個(gè) Configuration 對(duì)象,并成為了build()方法的入?yún)ⅰ?/p>
這個(gè)build(parser.parse()); 是
public SqlSessionFactory build(Configuration config) {return new DefaultSqlSessionFactory(config);}這個(gè)地方就是將之前已經(jīng)賦值好的Configuration 放在里面
public DefaultSqlSessionFactory(Configuration configuration) {this.configuration = configuration;}課間休息
地點(diǎn):長(zhǎng)沙
五、SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
至此 我們獲得了 SqlSessionFactory 對(duì)象,我們可以通過這獲取到mybatis操作數(shù)據(jù)庫(kù)的 SqlSession 對(duì)象。
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(); }我們這里調(diào)用的方法是這個(gè)哈
@Overridepublic SqlSession openSession() {// openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) return openSessionFromDataSource(configuration.getDefaultExecutorType(), null, false);}最后一個(gè)參數(shù)就是是否提交,如果不為true,我們做了修改or刪除,數(shù)據(jù)庫(kù)并不會(huì)修改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操作數(shù)據(jù)庫(kù)的 SqlSession 對(duì)象。
六、MyUserMapper mapper = sqlSession.getMapper(MyUserMapper.class);
/**檢索映射器。參數(shù):type – 映射器接口類類型參數(shù):<T> – 映射器類型返回:綁定到此 SqlSession 的映射器*/<T> T getMapper(Class<T> type);接下來開始套娃哈
我們實(shí)際調(diào)用的是它的實(shí)現(xiàn)類里的方法:
@Override public <T> T getMapper(Class<T> type) {return configuration.getMapper(type, this); }你看又牽扯到configuration對(duì)象了哈,知道它多重要了吧。
public <T> T getMapper(Class<T> type, SqlSession sqlSession) {return mapperRegistry.getMapper(type, sqlSession); }到了mapperRegistry 這個(gè)對(duì)象拉。 mapperRegistry的翻譯就是映射器注冊(cè)表 這個(gè)地方我目前還沒有搞懂它是什么時(shí)候注冊(cè)進(jìn)去的哈。
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);}}接下來繼續(xù)看這個(gè) 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);}當(dāng)我們看到這里的時(shí)候就知道m(xù)ybatis是通過反射和代理來進(jìn)行這些操作的哈。
真實(shí)執(zhí)行對(duì)象并不在,而是在 MapperProxy mapperProxy Mapper的代理對(duì)象中。
那個(gè)具體執(zhí)行的,等下一篇博客哈。我還有很多沒懂的。
七、XPathParser
public class XPathParser {private final Document document;private boolean validation;private EntityResolver entityResolver;private Properties variables;private XPath xpath; }-
Document(Document對(duì)象)
Document 對(duì)象代表整個(gè) XML 文檔,是一棵文檔樹的根,可為我們提供對(duì)文檔數(shù)據(jù)的最初(或最頂層)的訪問入口。
-
validation(是否開啟驗(yàn)證標(biāo)記)
該標(biāo)記表示設(shè)置解析器在解析文檔的時(shí)候是否校驗(yàn)文檔,在創(chuàng)建DocumentBuilderFactory實(shí)例對(duì)象時(shí)進(jìn)行設(shè)置。
-
EntityResolver (加載本地的DTD文件
如果解析mybatis-config.xml 配置文件,默認(rèn)聯(lián)網(wǎng)加載http://mybatis.org/dtd/mybatis-3- config.dtd 這個(gè)DTD 文檔,當(dāng)網(wǎng)絡(luò)比較慢時(shí)會(huì)導(dǎo)致驗(yàn)證過程緩慢。在實(shí)踐中往往會(huì)提前設(shè)置EntityResolver 接口對(duì)象加載本地的DTD 文件,從而避免聯(lián)網(wǎng)加載DTD文件。
-
XPath (XPath對(duì)象)
XPath 是一種為查詢XML 文檔而設(shè)計(jì)的語言,它可以與DOM 解析方式配合使用,實(shí)現(xiàn)對(duì)XML 文檔的解析。
-
variables(配置參數(shù)集合)。
對(duì)應(yīng)配置文件中節(jié)點(diǎn)下定義的鍵值對(duì)集合,包括通過url或者resource讀取的鍵值對(duì)集合。
八、XMLMapperEntityResolver
對(duì)這個(gè)我沒有深究。doc注釋就是這么一句話:MyBatis DTD 的離線實(shí)體解析器 說實(shí)話DTD都是我第一次見 🤦?
當(dāng)然百度是強(qiáng)大的。
它是EntityResolver子類,xml 的解析會(huì)基于事件觸發(fā)對(duì)應(yīng)的 Resolver 或 Handler,當(dāng)解析到 dtd 等外部資源時(shí)會(huì)
EntityResolver的resolveEntity方法。在XMLMapperEntityResolver.resolveEntity中,當(dāng)解析到 mybatis-3-config.dtd、
mybatis-3-mapper.dtd 等資源時(shí),會(huì)直接從 classpath 下的 org/apache/ibatis/builder/xml/ 路徑獲取資源,而不需要通過 url 獲取。
九、XMLMapperBuilder類
涉及到的類包括:
MapperBuilderAssistant:Mapper文件解析輔助類,包括了解析各種節(jié)點(diǎn)的方法。
BaseBuilder:XMLMapperBuilder與MapperBuilderAssistant的父類,保存了Configuration、TypeAliasRegistry、TypeHandlerRegistry三個(gè)屬性。
TypeAliasRegistry:別名對(duì)應(yīng)關(guān)系,保存了字符串與類的對(duì)應(yīng)信息,例如“String”字符串對(duì)應(yīng) String.class
TypeHandlerRegistry:注冊(cè)java.lang與java.sql類型對(duì)應(yīng)關(guān)系
Configuration:Mapper文件解析節(jié)點(diǎn)完成后,存儲(chǔ)解析后的屬性信息。
XMLStatementBuilder:解析SQL語句節(jié)點(diǎn)類,解析后存儲(chǔ)在Configuration下的mappedStatements屬性
XMLMapperBuilder用于解析Mapper文件,包括namespace、parameterMap、resultMap以及各種SQL(insert/uppdate/delete/select)
解析過程中主要是parse()方法,
解析Mapper文件后會(huì)存儲(chǔ)在MapperBuilderAssistant以及它父類BaseBuilder的實(shí)例下,主要是Configuration類
自言自語
我這算是自己的閱讀筆記哈,無聊讀著看看。
算是我第一次讀源碼的記錄。
大家一起加油哦。
總結(jié)
以上是生活随笔為你收集整理的Mybatis 源码探究 (3)创建 SqlSessionFactory对象 执行sqlSession.getMapper()方法的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Error creating bean
- 下一篇: Mybatis 源码探究 (4) 将sq