Mybatis源码阅读(一):Mybatis初始化1.1 解析properties、settings

*************************************优雅的分割线 **********************************

分享一波:程序员赚外快-必看的巅峰干货

如果以上内容对你觉得有用,并想获取更多的赚钱方式和免费的技术教程

请关注微信公众号:HB荷包
在这里插入图片描述
一个能让你学习技术和赚钱方法的公众号,持续更新
*************************************优雅的分割线 **********************************
SimpleExecutor

前言

笔者大概是从今年的5月份开始喜欢上源码阅读的,起初是阅读徐郡明前辈的《Mybatis技术内幕》入的坑,不得不说大佬就是大佬,书中讲得东西很细很全。半年过去了,笔者对mybatis略知一二,也开始在为公司搭架构,并且基于Mybatis写了一套框架,但是尽管如此还是感觉自己对于源码的理解稍微有点浅。好比是初高中学数学吧,光看例题不做题是记不住的,因此产生了为mybatis写注释的想法,想要通过写注释的过程,加强对mybatis的理解。虽然现在网上已经有了较全的mybatis中文注释,但是感觉还是经过自己手敲更能加强记忆,因此便挖下了这个大坑。笔者也希望可以在一年内把这个坑填完,后续关于其他技术的文章可能就比较少,大多数应该就都是mybatis源码阅读犀利了

在这里,附上我的码云地址(别问我为什么是码云而不是github,下半天代码下不动急死人)

mybatis中文注释

同时,我也很欢迎更多的初中级开发者投入到阅读源码的行列,并且很乐意大家在我的仓库上建立自己的分支,希望可以和大家一同进步。

入口

Mybatis

初始化入口文件是SqlSessionFactoryBuilder。该类通过调用XMLConfigBuilder.parse方法初始化配置文件。

public SqlSessionFactory build(Reader reader, String environment, Properties properties) {try {// 读取配置文件XMLConfigBuilder parser = new XMLConfigBuilder(reader, environment, properties);return build(parser.parse());} catch (Exception e) {throw ExceptionFactory.wrapException("Error building SqlSession.", e);} finally {ErrorContext.instance().reset();try {reader.close();} catch (IOException e) {// Intentionally ignore. Prefer previous error.}}}

在XMLConfigBuilder.parse方法中,会先校验配置文件是否已经解析过了,如果重复解析就抛出异常

public Configuration parse() {if (parsed) {// 已经解析过就不再解析。这里只解析一次throw new BuilderException("每个 XMLConfigBuilder 只能使用一次.");}parsed = true;// 获取configuration节点进行解析// mybatis解析配置文件使用的是XPathParser,这里的evalNode方法就是解析xml的代码// 这里对XPathParser不进行注释,这不属于mybatis的范畴(其实是懒。)parseConfiguration(parser.evalNode("/configuration"));return configuration;}

parseConfiguration方法中,传入configuration节点配置,对mybatis-config.xml文件中的该节点进行解析。解析结果会set到Configuration类中。今天只注释完了properties和settings两个节点的解析

 /*** 解析mybatis-config.xml文件** @param root*/private void parseConfiguration(XNode root) {try {// 解析properties节点。该节点用来引入外部的资源文件,如db.propertiespropertiesElement(root.evalNode("properties"));// 解析settings节点,校验配置中的配置项是否合法。该节点用来设置一些mybatis的配置项Properties settings = settingsAsProperties(root.evalNode("settings"));// 加载用户自己配置的虚拟文件系统loadCustomVfs(settings);// 加载日志loadCustomLogImpl(settings);// TODO 解析typeAliases节点,下次继续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 #631environmentsElement(root.evalNode("environments"));databaseIdProviderElement(root.evalNode("databaseIdProvider"));typeHandlerElement(root.evalNode("typeHandlers"));mapperElement(root.evalNode("mappers"));} catch (Exception e) {throw new BuilderException("Error parsing SQL Mapper Configuration. Cause: " + e, e);}}

先看propertiesElement方法,该方法用于解析properties节点。

/*** 解析mybatis-config.xml的properties节点* 将节点中所有的配置set到Configuration中** @param context* @throws Exception*/private void propertiesElement(XNode context) throws Exception {if (context != null) {// 解析拿到节点下的所有子节点配置Properties defaults = context.getChildrenAsProperties();// 获取properties节点的resource属性String resource = context.getStringAttribute("resource");// 获取properties节点的url属性。String url = context.getStringAttribute("url");if (resource != null && url != null) {// resource和url属性只能同时存在一个。throw new BuilderException("properties节点不能同时指定resource和url两个属性.");}// url和resource属性只能同时存在一个// 读取引入的资源文件所有属性,put到properties节点之下if (resource != null) {defaults.putAll(Resources.getResourceAsProperties(resource));} else if (url != null) {defaults.putAll(Resources.getUrlAsProperties(url));}Properties vars = configuration.getVariables();// 如果configuration之前已经有了配置,也put进去// put这些设置是为了能够保证后面set回configuration时可以set所有的配置if (vars != null) {defaults.putAll(vars);}parser.setVariables(defaults);// 将Properties节点下所有的配置set到configurationconfiguration.setVariables(defaults);}}

接着就是解析settings节点,该节点用于配置一些mybatis配置项

/*** 解析settings节点** @param context* @return*/private Properties settingsAsProperties(XNode context) {if (context == null) {return new Properties();}// 获取settings节点下所有的setting节点Properties props = context.getChildrenAsProperties();// 通过Configuration获取metaClass,用于方便对Configuration进行操作MetaClass metaConfig = MetaClass.forClass(Configuration.class, localReflectorFactory);for (Object key : props.keySet()) {// 遍历setting配置// 如果Configuration没有这个set方法,说明该配置是无效的if (!metaConfig.hasSetter(String.valueOf(key))) {throw new BuilderException("配置 " + key + " 无效. 请检查拼写是否正确.");}}// 校验完settings之后返回return props;}

解析完settings节点后,程序会加载用户配置的虚拟文件系统和日志。

/*** 加载用户自己设置的虚拟文件系统** @param props* @throws ClassNotFoundException*/private void loadCustomVfs(Properties props) throws ClassNotFoundException {// 从settings中拿到name是vfsImpl的配置节点String value = props.getProperty("vfsImpl");if (value != null) {String[] clazzes = value.split(",");for (String clazz : clazzes) {if (!clazz.isEmpty()) {@SuppressWarnings("unchecked")Class<? extends VFS> vfsImpl = (Class<? extends VFS>) Resources.classForName(clazz);// 加载文件系统,set到Configuration中configuration.setVfsImpl(vfsImpl);}}}}/*** 加载日志。代码比较简单* 就是从settings中拿到name为logImpl的配置项* 然后set到Configuration中去** @param props*/private void loadCustomLogImpl(Properties props) {Class<? extends Log> logImpl = resolveClass(props.getProperty("logImpl"));configuration.setLogImpl(logImpl);}

引申
上面的代码中使用到了MetaClass类和Configuration类。下面对这两个类进行解释。

首先是Configuration类。该类通过名称可以很明显的知道这是mybatis的配置类,对应的是mybatis-config.xml文件的配置。其中今天将properties和settings节点对应的字段进行注释。

public class Configuration {/*** mybatis-config.xml属性* settings节点* 允许嵌套语句中使用分页*/protected boolean safeRowBoundsEnabled;/*** mybatis-config.xml属性* settings节点* 是否开启自动驼峰命名规则映射* 即从经典数据库列名 a_column 到经典 Java 属性名 aColumn 的类似映射。*/protected boolean mapUnderscoreToCamelCase;/*** mybatis-config.xml文件下* settings节点* 当启用时,对任意延迟属性的调用会使带有延迟加载属性的对象完整加载;* 反之,每种属性将会按需加载。*/protected boolean aggressiveLazyLoading;/*** mybatis-config.xml文件下* settings节点* 是否允许单一语句返回多条结果集*/protected boolean multipleResultSetsEnabled = true;/*** mybatis-config.xml文件* settings节点* 允许 JDBC 支持自动生成主键*/protected boolean useGeneratedKeys;/*** mybatis-config.xml文件* settings节点* 使用列标签代替列名*/protected boolean useColumnLabel = true;/*** mybatis-config.xml文件* settings节点* 该配置影响的所有映射器中配置的缓存的全局开关*/protected boolean cacheEnabled = true;/*** mybatis-config.xml文件* settings节点* 指定当结果集中值为null的时候是否调用映射对象的set方法*/protected boolean callSettersOnNulls;/*** mybatis-config.xml文件* settings节点* 指定MyBatis增加到日志名称的前缀*/protected String logPrefix;/*** mybatis-config.xml文件* settings节点* 指定MyBatis所用日志的具体实现*/protected Class<? extends Log> logImpl;/*** mybatis-config.xml文件* settings节点* VFS含义是虚拟文件系统;* 主要是通过程序能够方便读取本地文件系统、FTP文件系统等系统中的文件资源。* Mybatis中提供了VFS这个配置。* 主要是通过该配置可以加载自定义的虚拟文件系统应用程序* 多个文件系统使用逗号隔开*/protected Class<? extends VFS> vfsImpl;/*** mybatis-config.xml文件* settings节点* mybatis利用本地缓存机制防止循环引用的加速重复嵌套查询。* 默认是SESSION,这种情况会缓存一个会话中执行的所有查询* 如果是STATEMENT,本地会话仅用在语句执行上* 对相同的SqlSession的不同调用将不会共享数据*/protected LocalCacheScope localCacheScope = LocalCacheScope.SESSION;/*** mybatis-config.xml文件* settings节点* 当没有为菜蔬提供特定的JDBC类型时* 为空值制定JDBC类型*/protected JdbcType jdbcTypeForNull = JdbcType.OTHER;/*** mybatis-config.xml* settings节点* 指定哪个对象的方法触发一次延迟加载*/protected Set<String> lazyLoadTriggerMethods = new HashSet<>(Arrays.asList("equals", "clone", "hashCode", "toString"));/*** mybatis-config.xml文件* settings节点* 设置超时时间*/protected Integer defaultStatementTimeout;/*** mybatis-config.xml文件* settings节点* 为驱动程序设置提示以控制返回结果的获取大小*/protected Integer defaultFetchSize;/*** mybatis-config.xml文件* settings节点* 配置默认的执行器。* SIMPLE 就是普通的执行器;* REUSE 执行器会重用预处理语句(PreparedStatements);* BATCH 执行器将重用语句并执行批量更新。*/protected ExecutorType defaultExecutorType = ExecutorType.SIMPLE;/*** mybatis-config.xml文件* settings节点* 指定 MyBatis 应如何自动映射列到字段或属性。* NONE 表示取消自动映射;* PARTIAL 只会自动映射没有定义嵌套结果集映射的结果集。* FULL 会自动映射任意复杂的结果集*/protected AutoMappingBehavior autoMappingBehavior = AutoMappingBehavior.PARTIAL;/*** mybatis-config.xml文件下* properties节点的所有配置* 以及该节点对应的resource和url的所有配置* 在XMLConfigBuilder.propertiesElement方法中进行初始化*/protected Properties variables = new Properties();/*** mybatis-config.xml文件* settings节点属性* 延迟加载的全局开关。* 当开启时,所有关联对象都会延迟加载。* 特定关联关系中可通过设置fetchType属性来覆盖该项的开关状态*/protected boolean lazyLoadingEnabled = false;/*** mybatis-config.xml文件* settings节点* 指定Mybatis创建具有延迟加载能力对象所用到的代理工厂*/protected ProxyFactory proxyFactory = new JavassistProxyFactory();/*** 将数据库类型转换成Java类型*/protected final TypeHandlerRegistry typeHandlerRegistry = new TypeHandlerRegistry(this);/*** 存储扫包得到的别名*/protected final TypeAliasRegistry typeAliasRegistry = new TypeAliasRegistry();}

而MetaClass是反射工具箱里的一个类。Reflector是Mybatis中反射模块的基础,每个Reflector对象都对应一个类,在该对象中缓存了反射操作需要使用的元信息,如:可读属性、可写属性、get、set方法等。ReflectorFactory接口主要实现了对Reflector对象的创建和缓存。而MetaClass则是对Reflector和reflectorFactory的封装,使其更方便通过反射去操作一个类。

这里就不帖MetaClass的代码了,感兴趣可以自行阅读。

结语

今天因为时间充裕所以写的博客比较清晰,后面可能会因为加班所以博客仅仅是对代码注释的复制粘贴,还希望读者可以谅解。这个坑我会继续填下去的。

最后需要提一下java里的一个容易被忽视的规范,也是面试、大学考试经常喜欢问的内容。

类中定义的成员变量也称之为“字段”,而属性则是指get和set方法。属性只与方法有关而与字段无关。如一个类中存在getName()和setName(String name)方法,不管该类中有没有name字段,我们都认为它有name这个属性。反之如果只有字段name而没有对应的get/set方法,则该类仅仅是有name这个字段而没有name属性。后面对于get/set方法我不会称之为属性,但是有必要分清楚这两个概念。
*************************************优雅的分割线 **********************************

分享一波:程序员赚外快-必看的巅峰干货

如果以上内容对你觉得有用,并想获取更多的赚钱方式和免费的技术教程

请关注微信公众号:HB荷包
在这里插入图片描述
一个能让你学习技术和赚钱方法的公众号,持续更新
*************************************优雅的分割线 **********************************
SimpleExecutor

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/536951.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

JavaScript异步基础

唯一比不知道代码为什么崩溃更可怕的事情是&#xff0c;不知道为什么一开始它是工作的&#xff01;在 ECMA 规范的最近几次版本里不断有新成员加入&#xff0c;尤其在处理异步的问题上&#xff0c;更是不断推陈出新。然而&#xff0c;我们在享受便利的同时&#xff0c;也应该了…

Flutter、ReactNative、uniapp对比

*************************************优雅的分割线 ********************************** 分享一波:程序员赚外快-必看的巅峰干货 如果以上内容对你觉得有用,并想获取更多的赚钱方式和免费的技术教程 请关注微信公众号:HB荷包 一个能让你学习技术和赚钱方法的公众号,持续更…

多线程中ThreadLocal的使用

*************************************优雅的分割线 ********************************** 分享一波:程序员赚外快-必看的巅峰干货 如果以上内容对你觉得有用,并想获取更多的赚钱方式和免费的技术教程 请关注微信公众号:HB荷包 一个能让你学习技术和赚钱方法的公众号,持续更…

注解版poi操作工具

*************************************优雅的分割线 ********************************** 分享一波:程序员赚外快-必看的巅峰干货 如果以上内容对你觉得有用,并想获取更多的赚钱方式和免费的技术教程 请关注微信公众号:HB荷包 一个能让你学习技术和赚钱方法的公众号,持续更…

Kali Linux 2019.1 发布,Metasploit 更新到 5.0 版本

百度智能云 云生态狂欢季 热门云产品1折起>>> Kali Linux 2019.1 发布了&#xff0c;Kali 前身 BackTrack&#xff0c;它是一个基于 Debian 的 Linux 发行版&#xff0c;主要用于信息安全行业&#xff0c;其包含了一系列安全、渗透测试和取证工具。此版本 Linux 内核…

peewee mysql_scrapy中利用peewee插入Mysql

前两天老大布置一个任务&#xff0c;说爬下来的数据要存入数据库中&#xff0c;丢给我一个peewee&#xff0c;说用这个。当时的我两眼一抹黑&#xff0c;这是个什么东西呀&#xff0c;我知道scrapy的数据存入数据库是在pipelines中进行设置但是peewee是什么东西呢。经过两天不懈…

Java版数据结构与算法——线性表

*************************************优雅的分割线 ********************************** 分享一波:程序员赚外快-必看的巅峰干货 如果以上内容对你觉得有用,并想获取更多的赚钱方式和免费的技术教程 请关注微信公众号:HB荷包 一个能让你学习技术和赚钱方法的公众号,持续更…

基于 CODING 的 Spring Boot 持续集成项目

本文作者&#xff1a;CODING 用户 - 廖石荣 持续集成的概念 持续集成(Continuous integration,简称 CI&#xff09;是一种软件开发实践&#xff0c;即团队开发成员经常集成他们的工作&#xff0c;通常每个成员每天至少集成一次&#xff0c;也就意味着每天可能会发生多次集成。每…

Mybatis组成部分

*************************************优雅的分割线 ********************************** 分享一波:程序员赚外快-必看的巅峰干货 如果以上内容对你觉得有用,并想获取更多的赚钱方式和免费的技术教程 请关注微信公众号:HB荷包 一个能让你学习技术和赚钱方法的公众号,持续更…

一年java工作经验-面试总结

*************************************优雅的分割线 ********************************** 分享一波:程序员赚外快-必看的巅峰干货 如果以上内容对你觉得有用,并想获取更多的赚钱方式和免费的技术教程 请关注微信公众号:HB荷包 一个能让你学习技术和赚钱方法的公众号,持续更…

linux mysql python包_03_mysql-python模块, linux环境下python2,python3的

---恢复内容开始---1、Python2 正常[rootIP ~]#pip install mysql-pythonDEPRECATION: Python 2.7 will reach the end of its life on January 1st, 2020. Please upgrade your Python as Python 2.7 wont be maintained after that date. A future version of pip will drop …

两年Java工作经验应该会些什么技术

*************************************优雅的分割线 ********************************** 分享一波:程序员赚外快-必看的巅峰干货 如果以上内容对你觉得有用,并想获取更多的赚钱方式和免费的技术教程 请关注微信公众号:HB荷包 一个能让你学习技术和赚钱方法的公众号,持续更…

centos 6 mysql 5.7.13 编译安装_Centos 6.5 下面 源码编译 安装 Mysql 5.7.13

安装软件依赖包yum -y install gcc gcc-c ncurses ncurses-devel cmake下载软件包cd /usr/local/srcwget https://downloads.mysql.com/archives/get/file/mysql-5.7.13.tar.gz --no-check-certificate下载 boost 库&#xff0c;MySQL 5.7.5 开始Boost库是必需的cd /usr/loca…

LeetCode 237. 删除链表中的节点(Python3)

题目&#xff1a; 请编写一个函数&#xff0c;使其可以删除某个链表中给定的&#xff08;非末尾&#xff09;节点&#xff0c;你将只被给定要求被删除的节点。 现有一个链表 -- head [4,5,1,9]&#xff0c;它可以表示为: 示例 1: 输入: head [4,5,1,9], node 5 输出: [4,1,9…

一年Java经验应该会些什么

*************************************优雅的分割线 ********************************** 分享一波:程序员赚外快-必看的巅峰干货 如果以上内容对你觉得有用,并想获取更多的赚钱方式和免费的技术教程 请关注微信公众号:HB荷包 一个能让你学习技术和赚钱方法的公众号,持续更…

mysql查询各类课程的总学分_基于jsp+mysql的JSP学生选课信息管理系统

运行环境: 最好是java jdk 1.8&#xff0c;我们在这个平台上运行的。其他版本理论上也可以。IDE环境&#xff1a; Eclipse,Myeclipse,IDEA都可以硬件环境&#xff1a; windows 7/8/10 2G内存以上(推荐4G&#xff0c;4G以上更好)可以实现&#xff1a; 学生&#xff0c;教师角色的…

三年java经验应该会什么?

*************************************优雅的分割线 ********************************** 分享一波:程序员赚外快-必看的巅峰干货 如果以上内容对你觉得有用,并想获取更多的赚钱方式和免费的技术教程 请关注微信公众号:HB荷包 一个能让你学习技术和赚钱方法的公众号,持续更…

python加法运算符可以用来连接字符串并生成新字符串_中国大学MOOCPython语言入门网课答案...

中国大学MOOCPython语言入门网课答案表达式int(40.5)的值为____________。表达式160.5的值为____________________。python程序只能使用源代码进行运行&#xff0c;不能打包成可执行文件。python语句list(range(1,10,3))执行结果为___________________。pip命令也支持扩展名为.…

全是满满的技术文档

*************************************话不多说-先上教程 ********************************** 完整躺赚教程(不需任何技术,照做就能赚钱):点击此处获取 提取码&#xff1a;6666 被动收入教程(需要一定的技术,会搭建服务器,会发布项目<教程里面会教你>):点击此处获取 提…

JavaScript面试的完美指南(开发者视角)

2019独角兽企业重金招聘Python工程师标准>>> 摘要&#xff1a; 面试季手册。 原文&#xff1a;javascript 面试的完美指南(开发者视角)作者&#xff1a;前端小智Fundebug经授权转载&#xff0c;版权归原作者所有。 为了说明 JS 面试的复杂性&#xff0c;首先&#x…