MyBatis源码初探
搭建好了 MyBatis的环境,接下来就是debug学习了,正常的一个main函数执行流程是,加载xml–>生成SqlSessionFactory–>生成SqlSession–>get到你的xml对应的mapper–>调用Mapper的方法。
那么这其中涉及到的MyBatis的类有Resource、SqlSessionFactory、SqlSession,这是我们能看见的,这其中当然也包括内部调用了MyBatis的别的类的方法,下面我们来一个一个看一看。
首先Resource没什么可说的就是加载进资源,目的是得到一个InputStream流,main方法里的代码:
String resource = "mybatis-config.xml";
InputStream inputStream = null;
try {
inputStream = Resources.getResourceAsStream(resource);
} catch (IOException e) {
e.printStackTrace();
}
得到InputStream用来干嘛呢?用来生成SqlSessionFactory,这里MyBatis用了建造者模式,它里面很多地方都用了这个设计模式,SqlSessionFactory是个接口它获取这个接口的实现是通过SqlSessionFactoryBbuilder来获取的
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(inputStream);
这个SqlSessionFactoryBbuilder里面有九个build方法,类图:
方法的参数各自不同,简单说来就是流、Properties和一个String类型表是数据库环境的字段,最终所有方法都会走到一个三个参数都有的build方法中,
public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties) {
SqlSessionFactory var5;
try {
XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties);
var5 = this.build(parser.parse());
} catch (Exception var14) {
throw ExceptionFactory.wrapException("Error building SqlSession.", var14);
} finally {
ErrorContext.instance().reset();
try {
inputStream.close();
} catch (IOException var13) {
;
}
在这个方法里面主要就是做了两件事,一件事是new了一个XmlConfigBuilder类,这个类首先是BaseBuilder的子类
boolean类型表是是否已经解析,还有一个XPath解析器,还有一个数据库的版本,在它内部的构造方法里面它做了这么几件事,第一它调用了它父类BaseBuiler的一个构造方法,传入的参数是它new了一个Configuration传了进去,
private XMLConfigBuilder(XPathParser parser, String environment, Properties props) {
super(new Configuration());
ErrorContext.instance().resource("SQL Mapper Configuration");
this.configuration.setVariables(props);
this.parsed = false;
this.environment = environment;
this.parser = parser;
}
这个Configuration也是MyBatis内部的一个类,这个类很重要用来保存MyBatis的配置数据,比如我们<set>标签里的节点,
对应我们的mybatis-config.xml

protected boolean cacheEnabled = true;
缓存标识,也就是说MyBatis默认启用了一级缓存,protected LocalCacheScope localCacheScope = LocalCacheScope.SESSION;
本地缓存的级别是Session,还提供了生成执行器Executor的方法,回到SqlSessionFactory里面new完XmlConfigBuilder类之后,会调用SqlSessionFactory里面一个build方法就是this.build传入的参数就是我们刚刚new的XMLcONFIGBuiler里面生成的Configuration对象,做了一件什么事呢?就是new了一个DefaultSqlSessionFactory类,
public SqlSessionFactory build(Configuration config) {
return new DefaultSqlSessionFactory(config);
}
DefaultSqlSessionFactory是MyBatis接口SqlSessionFactory的一个实现类,最主要的方法当然就是openSession的实现了,那么openSession有很多种实现,就是参数不同,参数共有三种configuration、事物隔离级别TransactionIsolationLevel和是否开始事物的标识autoCommit有传入启事物标识的,有传入执行器的,等等。那么所有的openSession其实也都是调用它内部的一个所有参数都传的一个方法叫做openSessionFromSource三个参数就是,
private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) {
Transaction tx = null;
DefaultSqlSession var8;
try {
Environment environment = this.configuration.getEnvironment();
TransactionFactory transactionFactory = this.getTransactionFactoryFromEnvironment(environment);
tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);
Executor executor = this.configuration.newExecutor(tx, execType);
var8 = new DefaultSqlSession(this.configuration, executor, autoCommit);
} catch (Exception var12) {
this.closeTransaction(tx);
throw ExceptionFactory.wrapException("Error opening session. Cause: " + var12, var12);
} finally {
ErrorContext.instance().reset();
}
return var8;
}
那么这个里面它其实就做了一件事就是new了一个DefaultSqlSession由此那么SqlSessionFactory是接口,SqlSession是接口,那么我们默认情况下,MyBatis都会创建一个接口的默认实现,比如DefaultSqlSessionFactory,这里面又有一个DefaultSqlSession,这个DefaultSqlSession的构造方法是三个参数configuration、executor执行器和autoCommint是否自动提交,
public DefaultSqlSession(Configuration configuration, Executor executor, boolean autoCommit) {
this.configuration = configuration;
this.executor = executor;
this.dirty = false;
this.autoCommit = autoCommit;
}
那么我们来看DefaultSqlSessionFactory
executor怎么获取的呢,通过configuration来获取,这Configuration类的片段:
public Executor newExecutor(Transaction transaction, ExecutorType executorType) {
executorType = executorType == null ? this.defaultExecutorType : executorType;
executorType = executorType == null ? ExecutorType.SIMPLE : executorType;
Object executor;
if (ExecutorType.BATCH == executorType) {
executor = new BatchExecutor(this, transaction);
} else if (ExecutorType.REUSE == executorType) {
executor = new ReuseExecutor(this, transaction);
} else {
executor = new SimpleExecutor(this, transaction);
}
if (this.cacheEnabled) {
executor = new CachingExecutor((Executor)executor);
}
Executor executor = (Executor)this.interceptorChain.pluginAll(executor);
return executor;
}
也是没有指定的话,MyBatis会默认给一个,就是SimpleExecutor类,这个类实现了Executor这个接口,也是MyBatis提供的三个Executor实现类之一,那么这个也值得一说,我们今天先不看,免得迷失在一堆类、方法的调用中,越来越乱,还是顺着一条直线放下走。到此我们就可以调用openSession方法来获取一个SqlSession对象了,然后利用SqlSession的getMapper方法获取Mapper,调用Mapper的方法来和数据库通信,就是增删改查嘛,至此,一个大流程,我们梳理完了,这其中还有还多细节,我们没有关注,比如:一级缓存,缓存在哪里做的?Mapper是利用动态代理来实现的,那么具体是怎么实现的呢?最后又是怎么和JDBC包装来访问的数据库呢?事物机制是怎么做的呢?这些问题都要看,所以这只是万里长征第一步,接下来我们在带着这些问题逐一去探索吧,今天先写到这里。
本文详细介绍了MyBatis框架的初始化过程,从加载配置文件到创建SqlSessionFactory及SqlSession对象,逐步剖析了MyBatis的内部实现机制,包括资源加载、配置解析、会话工厂与会话创建等关键步骤。
843

被折叠的 条评论
为什么被折叠?



