【一线大厂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来完成反射方法的调用的