概述
-
Mybatis作为一个SQL管理和执行框架,在web应用程序当中充当数据库访问中间件的角色,即应用程序在接收到请求时,通过DAO层方法从mybatis获取一个数据库连接,然后通过该连接将对应的SQL发送给数据库执行,最后获取返回结果。同时可以通过该连接发送多条SQL,即发送多个请求给数据库,所以该数据库连接的作用就相当于web浏览器中的一个会话。
-
基于这个业务背景,在mybatis的设计中使用SqlSession来代表该会话,其中在内部封装了一个数据库连接。同时抽象了一个SqlSessionFactory,即sqlSession工厂类,由SqlSessionFactory统一加载mybatis框架的整体配置和mapper.xml的SQL配置,包括提供数据库连接的数据源的引用,mapper.xml的SQL与Java的对应接口和方法的映射关系。
-
加载完成之后,就可以在应用程序当中直接通过SqlSessionFactory获取一个SqlSession,然后指定需要执行的mapper接口,调用对应的方法,由SqlSession通过SqlSessionFactory引用获取加载好的mapper.xml和mapper接口的映射关系,从而获取该方法对应的需要执行的SQL,最后通过sqlSession自身绑定的数据库连接来执行这条SQL。
-
基于以上设计,在不使用spring的时候,应用程序的使用示例如下:
String resource = "org/mybatis/example/mybatis-config.xml"; InputStream inputStream = Resources.getResourceAsStream(resource); SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); SqlSession session = sqlSessionFactory.openSession(); try { BlogMapper mapper = session.getMapper(BlogMapper.class); Blog blog = mapper.selectBlog(101); } finally { session.close(); }
SqlSessionFactory的初始化
-
由以上分析可知,mybatis框架在使用方面,第一步需要完成的是SqlSessionFactory对象的创建:具体为读取配置文件mybatisConfig.xml并加载为SqlSessionFactory对象的一个配置性质属性Configuration来维护,对应mapper.xml则生成内部是MapperProxy代理对象。
-
mybatis提供了一个SqlSessionFactoryBuidler,基于构造者模式来完成SqlSessionFactory对象的创建。核心源码实现如下:核心逻辑为通过builder包的xml子包的XMLConfigBuidler解析mybatisConfig.xml对象,生成对应的Configuration对象,然后将该Configuration对象作为参数创建SqlSessionFactory对象。
// 解析mybatisConfig.xml配置文件创建SqlSessionFactory, // 其中再mybatisConfig.xml内部存在mapper节点来指定mapper.xml文件的配置位置 public class SqlSessionFactoryBuilder { // 将mybatisConfig.xml对应的InputStream作为参数 public SqlSessionFactory build(InputStream inputStream) { return build(inputStream, null, null); } ... // 使用XMLConfigBuilder来解析mybatisConfig.xml文件 public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties) { try { XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties); // 调用parse方法完成xml文件的解析并创建对应的Configuration对象 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. } } } // 创建SqlSessionFactory对象实例, // 使用的是接口的默认实现类DefaultSqlSessionFactory public SqlSessionFactory build(Configuration config) { return new DefaultSqlSessionFactory(config); } }
XML文件解析器XMLConfigBuilder
-
由以上分析可知,配置文件mybatisConfig.xml主要通过XMLConfigBuilder来解析,具体为parse方法,然后生成对应的Configuration对象,XMLConfigBuilder的parse方法实现如下:
public Configuration parse() { if (parsed) { throw new BuilderException("Each XMLConfigBuilder can only be used once."); } parsed = true; parseConfiguration(parser.evalNode("/configuration")); return configuration; } private void parseConfiguration(XNode root) { try { // 以下方法的参数都是对应mybatisConfig.xml文件中的一个节点 //issue #117 read properties first propertiesElement(root.evalNode("properties")); Properties settings = settingsAsProperties(root.evalNode("settings")); loadCustomVfs(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 #631 environmentsElement(root.evalNode("environments")); databaseIdProviderElement(root.evalNode("databaseIdProvider")); typeHandlerElement(root.evalNode("typeHandlers")); // 解析mybatisConfig.xml的mappers标签 mapperElement(root.evalNode("mappers")); } catch (Exception e) { throw new BuilderException("Error parsing SQL Mapper Configuration. Cause: " + e, e); } } -
在内部主要是通过parseConfiguration方法来解析mybatisConfig.xml的各个节点,然后填充到Configuration对象中。
-
其中对应mapper.xml文件的解析主要是通过mapperElement方法来实现,主要为根据mapper.xml的namespace对应的类全限定名映射到对应的mapper接口,使用内部的buiding包的MapperProxy代理对象来表示,该代理对象集合为对应Configuration对象的mapperRegistry。其次是解析内部的SQL配置,使用mapping包的MappedStatement对象来表示,该代理对象集合则对应Configuration对象的mappedStatements。具体在后面的文章详细分析mapper.xml的解析。
Configuration配置加载
-
每个SqlSessionFactory关联一个mybatisConfig.xm配置文件,在SqlSessionFactory类对象内部是通过属性Configuration对象来保存这些配置信息。
public class DefaultSqlSessionFactory implements SqlSessionFactory { private final Configuration configuration; // 只有这个构造函数,使用Configuration存放mybatisConfig.xml中的配置信息 public DefaultSqlSessionFactory(Configuration configuration) { this.configuration = configuration; } ... } -
SqlSessionFactoryBuilder在创建SqlSessionFactory对象时,调用XMLConfigBuilder的parse方法来解析mybatisConfig.xml生成Configuration对象,然后将该Configuration对象作为参数创建SqlSessionFactory对象。
-
mybatisConfig.xml文件的每个节点都对应Configuration对象的一个属性,针对以上所分析的mapper.xml的namespace对应的mapper接口的映射MapperProxy,SQL语句对应的MappedStatement,具体如下:
public class Configuration { // 主要存放数据源引用,如通过数据源获取数据库连接 protected Environment environment; ... // 一级Cache默认为SESSION级别 protected LocalCacheScope localCacheScope = LocalCacheScope.SESSION; ... // 维护mapper接口对应的代理对象和mapper.xml文件映射,以及对象方法和SQL之间的映射 protected final MapperRegistry mapperRegistry = new MapperRegistry(this); ... // mapper接口方法的全限定名作为key,如com.xieyz.demo.mapper.UserDAO.getUser,value为SQL语句包装对象 protected final Map<String, MappedStatement> mappedStatements = new StrictMap<MappedStatement>("Mapped Statements collection"); ... }
总结
基于以上分析可知,mybatis框架的启动加载是基于SqlSessionFactoryBuilder的build方法调用:通过XMLConfigBuidler解析配置文件mybatisConfig.xml,创建并填充配置数据到Configuration对象,然后将该Configuration对象作为参数,创建SqlSessionFactory对象,即在SqlSessionFactory对象内部维护该Configuration对象引用,由于SqlSessionFactory创建的每个SqlSession对象内部都维护了SqlSessionFactory对象的引用,故SqlSession对象可以通过SqlSessionFactory对象间接引用Configuration对象,从而获取配置信息,如mapper接口对应的代理对象mapperProxy,mapper接口方法对应的SQL代理对象mappedStatement。






还没有评论,来说两句吧...