思维导图手撕MyBatis源码

news/2024/11/29 20:52:33/

文章目录

  • 前置准备
  • 通过类加载器读取配置文件流
  • 创建sqlSessionFactory
    • 建造者模式的使用
  • 打开SqlSession
  • 获取Mapper接口对象
  • 执行Mapper接口方法

前置准备

既然要读MyBatis的源码,那么我们就要先弄清楚MyBatis的入口在哪。这里我们直接写一个标准的MyBatis使用程序,以此来寻找入口分析源码:

//第一步:读取mybatis-config.xml配置文件
InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml");//第二步:构建SqlSessionFactory
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);//第三步:打开SqlSession
SqlSession session = sqlSessionFactory.openSession();//第四步:获取Mapper接口对象
UUserInfoMapper uUserInfoMapper = session.getMapper(UUserInfoMapper.class);//第五步:调用Mapper接口对象的方法操作数据库;
UUserInfo uUserInfo = uUserInfoMapper.selectByPrimaryKey(1);//第六步:业务处理
log.info("查询结果: " + uUserInfo.getId() + "--" + uUserInfo.getPhone());

通过类加载器读取配置文件流

在这里插入图片描述

这个地方你替换成为这个也是可以的;

//第一步:读取mybatis-config.xml配置文件
InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml");
//InputStream inputStream = App.class.getClassLoader().getResourceAsStream("mybatis-config.xml");

或者

Thread.currentThread().getContextClassLoader().getResourceAsStream("mybatisConfig.xml")

这个方法更加通用,在web环境和java环境下均可以使用

创建sqlSessionFactory

//第二步:构建SqlSessionFactory
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);

这个地方使用了建造者模式。build方法返回的实际上是一个DefaultSqlSessionFactory对象(实现了SqlSessionFactory)并持有一个Configuration的引用:
在这里插入图片描述

在这里插入图片描述
完整过程如下:
在这里插入图片描述
总结:

千层饼读法:

第一层:

  • new SqlSessionFactoryBuilder().build(InputStream)创建了一个SqlSessionFactory对象

第二层:

  • 创建XMLConfigBuilder 对象:new XMLConfigBuilder(Reader reader, String environment, Properties props)
  • XMLConfigBuilder.parse():解析xml文件获得Configuration对象
  • new DefaultSqlSessionFactory(Configuration):new 了一个DefaultSqlSessionFactory传入了刚才解析出来的Configuration对象,然后返回这个SqlSessionFactory对象

第三层:解析new XMLConfigBuilder(Reader reader, String environment, Properties props)方法

  • new XMLMapperEntityResolver():创建了一个XML映射器实体解析器
  • new XPathParser(InputStream inputStream, boolean validation, Properties variables, EntityResolver entityResolver):传入XML映射器实体解析器,构造出XPathParser
  • 通过XMLConfigBuilder(XPathParser parser, String environment, Properties props)构造器返回XMLConfigBuilder对象

解析:
XPathParser:XPathParser核心功能是封装了XPath,对表达式进行解析,并转化成为指定的数据类型,其属性如下;

    private Document document;private boolean validation;private EntityResolver entityResolver;private Properties variables;private XPath xpath;
  • document:要解析的xml文件被转化成的Document对象。
  • validation:获取document时是否要开启校验,开启校验的话会根据xml配置文件中定义的dtd文件校验xml格式,默认不开启校验。
  • entityResolver:实体解析器,用于从本地工程目录中引入dtd文件,而不是根据网络URL去加载校验文件。
  • variables:mybatis-config.xml配置文件中,节点引入或定义的属性。
  • xpath:封装的XPath对象,用来解析表达式。

所有构造函数做的事都如下所示:

    public XPathParser(InputStream inputStream, boolean validation, Properties variables) {commonConstructor(validation, variables, null);this.document = createDocument(new InputSource(inputStream));}
  • commonConstruct()方法初始化了除Document之外的其他类属性,XPath是通过XPathFactory创建的
  • createDocument用来初始化document
    在这里插入图片描述
    // 将InputSource对象转化为Document对象private Document createDocument(InputSource inputSource) {try {DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();factory.setValidating(validation);   // 是否要校验由外界传入的值确定factory.setNamespaceAware(false);    // 如果要使用mybatis的XSD Schema,此处必须设为true,但源码里是false,说明官方默认用dtd来做校验,舍弃了XSD Schemafactory.setIgnoringComments(true);   // 默认忽略注释factory.setIgnoringElementContentWhitespace(false);  // 只有开启校验才能去除xml中的空白节点,但是不知是否开启校验,所以这里设为了falsefactory.setCoalescing(false);factory.setExpandEntityReferences(true);    // 默认开启使用扩展实体引用DocumentBuilder builder = factory.newDocumentBuilder();builder.setEntityResolver(entityResolver);  // 使用传入的EntityResolver对象builder.setErrorHandler(new ErrorHandler() {  // 定义解析xml文档的错误处理器,如果发生了错误或致命错误则直接抛出异常,如果是警告默认不做处理@Overridepublic void error(SAXParseException exception) throws SAXException {throw exception;}@Overridepublic void fatalError(SAXParseException exception) throws SAXException {throw exception;                    }               @Overridepublic void warning(SAXParseException exception) throws SAXException {}});return builder.parse(inputSource);  //开始解析} catch (Exception e) {e.printStackTrace();}return null;}
  • 要解析一个xml文件为Document,需要DocumentBuilder类的支持,实际上DocumentBuilder本身就支持多种形式的xml的解析,这里之所以先统一转成InputSource,大概是为了代码简洁一点吧!
  • DocumentBuilder对象由DocumentBuilderFactory创建,DocumentBuilderFactory可以设置是否校验、是否开启命名空间、是否忽略注释空白节点等,详细可以看上面源码注释。
  • 如果开启了xml格式校验,DocumentBuilder就要设置实体解析器,这里使用了构造函数传入的实体解析器,如果解析xml过程中检测到格式不对或者其他报错,则需要抛出异常信息,所以这里又设置了错误处理器ErrorHandler,对于错误和致命错误直接抛出异常,对于警告则忽略。

MyBatis解析配置文件的本质就是为了获得Configuration对象;
Configuration 对象可以理解是mybatis的XML配置文件在程序中的化身,是MyBatis非常重要的一个对象,里面封装了MyBatis的整个配置信息

建造者模式的使用

DefaultSqlSessionFactory 类的有参构造需传入 Mybatis 核心配置类 Configuration 的对象作为参数,而 Configuration 内容很多,初始化比较麻烦,因此使用了专门的建造者 XMLConfigBuilder 进行创建

把源码看过一遍之后我们大概可以看出来建造者模式的使用结构:

在这里插入图片描述

  • 在Mybatis环境的初始化过程中,SqlSessionFactoryBuilder会调用XMLConfigBuilder读取所有的MybatisMapConfig.xml和所有的Mapper.xml文件,构建Mybatis运行的核心对象Configuration对象,然后将该Configuration对象作为参数构建一个SqlSessionFactory对象。
  • 其中XMLConfigBuilder在构建Configuration对象时,也会调用XMLMapperBuilder用于读取*Mapper文件
  • 而XMLMapperBuilder会使用MapperAnnotationBuilder(注解开发)或者XMLStatementBuilder(xml开发)来读取和build所有的SQL语句。

其中在XMLConfigBuilder中的parseConfiguration方法中对Configuration的属性进行装配:
在这里插入图片描述
这里就对应了xml配置文件
在这里插入图片描述
通过以上源码,我们就能看出,在mybatis的配置文件中:

  • configuration节点为根节点。
  • 在configuration节点之下,我们可以配置10个子节点, 分别为:properties、typeAliases、plugins、objectFactory、objectWrapperFactory、settings、environments、databaseIdProvider、typeHandlers、mappers。顺序遵从dtd文件约束,解析配置文件完成了之后,都会装配到configuration
  • Configuration作用:mybatis核心的配置文件内容 ,使用xml转换bean

我们debug到这个方法,可以看到configuration对象的内部结构:
在这里插入图片描述

总结一下:

XMLConfigBuilder 类负责创建复杂对象 Configuration,可以视为具体建造者角色,而SqlSessionFactoryBuilder则是以封装式构建 SqlSessionFactory 实例,相当于简化的建造者模式。

打开SqlSession

第一层:

//第三步:打开SqlSession
SqlSession session = sqlSessionFactory.openSession();

第二层:

  • 调用openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit)返回SqlSession 对象

第三层:

  • configuration.getEnvironment():从configuration配置对象中获取环境environment信息

    • 相当于我们xml文件中的
      在这里插入图片描述
    • java中的模型类:
      在这里插入图片描述
  • getTransactionFactoryFromEnvironment(environment):根据环境environment信息获取事务工厂TransactionFactory

  • transactionFactory.newTransaction(DataSource dataSource, TransactionIsolationLevel level, boolean autoCommit):根据数据源、事务隔离级别、是否自动提交来创建事务。其本质就是new了一个JDBC事务
    在这里插入图片描述

  • Executor Configuration.newExecutor(Transaction transaction, ExecutorType executorType):根据执行器类型和事务创建执行器Executor对象

    • 默认使用ExecutorType.SIMPLE型
    • 如果配置了二级缓存,则会将执行器进行包装:executor = new CachingExecutor(executor)
      在这里插入图片描述
    • 将执行器加入拦截器链,循环遍历执行拦截器
      在这里插入图片描述
      • 这个interceptors是在xml文件中配置的
        在这里插入图片描述
  • DefaultSqlSession(Configuration configuration, Executor executor, boolean autoCommit):根据configuration和Executor创建一个默认的DefaultSqlSession对象并返回。

然后我们来看看详细过程:
在这里插入图片描述

获取Mapper接口对象

//第四步:获取Mapper接口对象
UUserInfoMapper uUserInfoMapper = session.getMapper(UUserInfoMapper.class);

详细过程如下:
在这里插入图片描述

执行Mapper接口方法

List<Stu> stus = mapper.selectSome(1);

在这里插入图片描述

未完待续。。。


http://www.ppmy.cn/news/41669.html

相关文章

《2023游戏行业热点趋势报告》|Party Game游戏成为新趋势,备受消费者瞩目

过去的2022年&#xff0c;在各路重拳下&#xff0c;我们目睹了游戏行业的“焦虑”&#xff1a; 版号停发&#xff0c;版号数量缩减&#xff1b; 整个行业8年内首次下滑&#xff0c;玩家数量减少&#xff1b; 市场空间被挤压&#xff0c;买量成本激增&#xff1b; ...... 游…

Spring Cloud Sleuth 实现微服务链路跟踪

为什么要实现微服务链路追踪 一个完整的微服务系统一般由成百上千&#xff0c;甚至几万、几十万、几百万的服务实例构成。在这种规模下&#xff0c;如果出现问题&#xff0c;则准确跟踪问题点会十分困难。所以&#xff0c;需要用链路跟踪工具来监控微服务状态&#xff0c;当出现…

企业电子招投标采购系统——功能模块功能描述+数字化采购管理 采购招投标

​ 功能模块&#xff1a; 待办消息&#xff0c;招标公告&#xff0c;中标公告&#xff0c;信息发布 描述&#xff1a; 全过程数字化采购管理&#xff0c;打造从供应商管理到采购招投标、采购合同、采购执行的全过程数字化管理。通供应商门户具备内外协同的能力&#xff0c;为外…

3.8——友元

类的主要特点之一是信息隐藏和封装&#xff0c;即类的私有成员和保护成员只能在定义的范围内使用&#xff0c;也就是说私有成员和保护成员只能通过类的成员函数来访问。但是&#xff0c;有时候我们在类外也需要访问私有成员数据或保护成员数据怎么办。这时我们就要通过友元函数…

ffmpeg 给视频或者图片添加水印和马赛克的方法

可以使用 FFmpeg 给视频或图片添加水印和马赛克。以下是具体方法&#xff1a; 添加水印 如果需要给视频添加水印&#xff0c;可以使用 overlay 滤镜。该滤镜将两个输入叠加在一起&#xff0c;即将视频和水印画面结合在一起。以下是一个简单的例子&#xff1a; ffmpeg -i inpu…

Linux内核调度策略

linux内核的三种调度方法&#xff1a; 1&#xff0c;SCHED_OTHER 分时调度策略&#xff0c; 2&#xff0c;SCHED_FIFO实时调度策略&#xff0c;先到先服务 3&#xff0c;SCHED_RR&#xff08;Round-Robin&#xff09;实时调度策略&#xff0c;时间片轮转 实时进程将得到优先调…

优维可观测轴心产品大观:HyperInsight超融合持续可观测解决方案

随着Kubernetes得到越来越广泛的采用&#xff0c;企业软件系统正在向复杂的云原生架构进行革命性转变。应用形式呈现有Web、APP、小程序等多种形式&#xff0c;访问的网络有4G、5G、Wi-Fi等。企业用云也从单一云时代&#xff0c;逐渐来到混合多云时代。在这些庞大复杂的多云环境…

SONiC系列:supervisor技术详解

文章目录概念supervisor简介supervisor特性主要组件debian仓库里的版本核心组件——supervisord核心组件——supervisorctl配置详解systemctl系统服务supervisord服务端supervisorctl客户端子进程配置案例测试项目安装supervisor修改配置守护一个shell查看子进程动态SONiC实战设…