从Mybatis源码到Spring动态数据源底层原理分析系列一、Mybatis初始化源码浅析

【一线大厂Java面试题解析+后端开发学习笔记+最新架构讲解视频+实战项目源码讲义】

**开源地址:https://docs.qq.com/doc/DSmxTbFJ1cmN1R2dB **

------ CustomerMapper.xml ------

<?xml version="1.0" encoding="UTF-8"?>

select remarks

from customer where id = #{id}

复制代码

2.3、config文件分析

其实mybatis在初始化的时候就是对上面这些配置文件进行xml解析而已, 将它们解析成一个个的java对象存储起来, 首先我们来看看mybatis-con.xml这个文件, configuration对象, 故名思义, 就是mybatis的配置, 在mybatis初始化的时候, 会将其解析成一个Configuration对象, 而environment对象也是一样, 会将其解析成一个Environment对象, environments标签中可以配置多个environment标签, 通过default来表示默认生效哪一个, 在environment中, 则表示的是当前环境下的数据库配置信息, 其中包括事务工厂(用于创建事务的factory)、数据源等, 所以以上配置映射成java对象即如下:

class Configuration {

private Environment environment;

private Map<String, MappedStatement> mappedStatements;

}

class Environment {

private TransactionFactory transactionFactory;

private DataSource dataSource;

}

复制代码

非常清晰的映射关系, 一个环境里面包含了数据源以及事务工厂, 如果不是很理解事务工厂的用处, 可以先不用着急, 我们后面的文章会进行详细的分析, 在本小节, 只是为了告诉大家, 一个mybatis的配置文件, 最终其实是以java对象保存的, 而xml中的标签层级, 其实就是对应了对象中的属性层级

2.4、mapper文件分析

对于xxxMapper.xml这些文件, mybatis中通过mapper标签的namespace + select / update等标签中的id构成一个唯一标识(假设为statementId), 每一个sql标签以MappedStatement的对象的形式保存在Configuration对象中, 在上面的Configuration中, 以statementId -> MappedStatement 形成一个映射关系, 而MappedStatement中则存储了一个select等类型的标签中的所有内容, 比如parameterType, resultType, resultMap, sql等, 当我们在触发sql执行的时候, 即通过statementId找到对应的MappedStatement, 取出里面的sql来执行, 然后利用resulthandler以及resultType或者resultMap等信息对结果集进行封装映射, 最后返回

在日常的开发中, 我们面向接口编程, 会定义一个个的Mapper接口类, 当执行这些接口方法的时候, 代理对象会利用接口的全路径类名 + 接口方法名构成一个statementId, 进而获取到对应的MappedStatement, 然后从中提取sql, 执行sql, 最后将结果集利用MappedStatement中的保存的resultMap等信息映射成对应的java对象

2.5、总结

mybatis-con.xml这样的配置文件, 以Configuration对象存储, 表示整个mybatis的配置文件, 里面包含了一个环境(当前mybatis中对应的数据源以及事务工厂)以及所有的Mapper文件中一个个sql标签解析出来后的MappedStatement对象, xml文件的层次对应了java对象中的属性层次, MappedStatement中包含了一个sql标签需要执行的所有信息, 包括sql、动态sql解析需要的数据以及通过jdbc查询到的结果集如果处理的信息

3、配置文件初始化源码分析


3.1、代码引入

public static void main(String[] args) {

SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream( “mybatis-con.xml” ) );

SqlSession sqlSession = sqlSessionFactory.openSession();

List objectList = sqlSession.selectList(“com.fightzhong.mapper.CustomerMapper.selectRemarksById”, 12602611);

}

复制代码

通过上面三行代码, 我们完成了mybatis的初始化, 以及执行了上面mapper中的一个select语句, 可以看到, 通过将mybatis-con.xml这个配置文件以流的形式读取, 然后利用这个文件流开始读取mybatis的配置, 我们可以先不用理会什么是SqlSession以及SqlSessionFactory, 在mybatis源码分析的最后, 我才会跟大家说明这两个东西是什么, 如果没有对底层依赖的组件有一个清晰的了解, 那么我们也不会深刻的了解到这两个类的真正作用! 不过SqlSessionFactoryBuilder.build方法却是我们需要进行分析的, 注意, 不要因为不知道SqlSessionFactoryBuilder和SqlSession是什么而感到烦恼!

3.2、build方法开始构建Configuration对象

public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties) {

XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties);

return build(parser.parse());

}

复制代码

可以看到, build方法调用到最后, 就是创建了一个XMLConfigBuilder, 然后调用它的parse方法创建了Configuration对象而已, build方法的参数inputStream就是配置文件的文件流, environment字段就是表示我们期望生效标签中的哪个环境

3.3、parse方法开始构建Configuration对象

public Configuration parse() {

parseConfiguration(parser.evalNode(“/configuration”));

return configuration;

}

private void parseConfiguration(XNode root) {

propertiesElement(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);

environmentsElement(root.evalNode(“environments”));

databaseIdProviderElement(root.evalNode(“databaseIdProvider”));

typeHandlerElement(root.evalNode(“typeHandlers”));

mapperElement(root.evalNode(“mappers”));

}

复制代码

非常清晰的xml解析过程, 最顶层解析configuration标签, 得到一个root(XNode), 如果有接触过xml解析, 或者有学过前端dom编程的同学就不会感到陌生, 就像前端的document.getxxx()方法的调用, 得到根节点后, 开始解析里面的一个个标签

properties: 解析properties标签, 将里面的一个个键值对取出来以Properties对象的形式保存到Configuration中

settings: 解析settings标签, 将一个个的mybatis配置设置到Configuration中, loadCustomVfs、 loadCustomLogImpl都是对settings标签的解析, settingsElement方法也是, 这个方法就是读取settings标签中的一个个配置, 然后调用configuration.setXXXX()方法进行设置

typeAliases: 别名的解析

plugins: mybatis插件的解析, 如果有使用过mybatis插件, 那么对于这里面的代码就会比较清晰, 其实就是一个个的拦截器而已, 大家有兴趣可以做一下mybatis插件的实践, 从而能够更加清楚的认识插件的作用

objectFactory: 在mybatis对sql执行完毕之后, 会对结果集进行处理, 创建一个个的对象并返回, 创建对象就是利用反射完成的, objectFactory即对象工厂, 完成对象反射的创建, 接口方法非常简单, 就是提供一个Class对象, 然后根据这个Class对象创建对应的实体类对象, 默认是DefaultObjectFactory, mybatis提供了扩展, 允许开发者自己定义对象创建的工厂类

objectWrapperFactory: 创建ObjectWrapper的工厂类, ObjectWrapper即对一个对象进行了包装, 然后利用该类中提供的反射方法对该对象进行反射属性的操作, 比如setXXX, getXXX (如果有了解过spring源码的话, 就会发现, 在spring创建bean对象的时候也有一个类似的功能类), 默认的实现类为DefaultObjectWrapperFactory, 里面没有任何功能, 该类是mybatis提供给开发者的扩展功能

reflectorFactory: ReflectorFactory工厂的解析, 用于创建Relector对象, 每个Relector对象中包含了一个class对象, 以及这个类中所有的set、get方法, set方法参数集合、get方法参数集合, 这个类其实就是反射工具类, 只需要提供一个对应的对象, 然后就能利用Relector完成反射方法的调用, 同样有默认的实现DefaultReflectorFactory, 其实ObjectWrapper最还是通过Reflector来完成反射方法的调用的

  • 6
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值