MyBatis源代码解析 配置文件解析

本文详细解析了MyBatis配置文件的处理流程,包括通过SqlSessionFactoryBuilder构建过程,解析XML配置,注册别名、插件及工厂类,以及设置环境等关键步骤。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、解析流程

1、SqlSessionFactoryBuilder#build方法

2、build方法内部通过XMLConfigBuilder#parse解析

3、parse方法内部调用parseConfiguration方法,通过xml解析器获取xml的头节点<configuration/>

4、parseConfiguration方法内部调用多个方法分别解析不同节点,返回Configuration实例

5、SqlSessionFactoryBuilder#build方法获取Configuration实例,并实例化DefaultSqlSessionFactory实例返回

二、解析类

0x01 BaseBuilder类

作用:解析类的基础类,构造器需要Configuration实例,然后通过该实例设置TypeAliasRegistry和TypeHandlerRegistry

子类:

  • XMLConfigBuilder
  • XMLMapperBuilder
  • XMLStatementBuilder
  • XMLScriptBuilder
  • SqlSourceBuilder
  • ParameterMappingTokenHandler
  • MapperBuilderAssistant

0x02 Configuration类

作用:mybatis的配置类,所有配置都在这里,通常new一个实例给BaseBuilder类

初始化流程:

  • 初始化TypeAliasRegistry
  • 初始化TypeHandlerRegistry

0x03 XMLConfigBuilder类

作用:解析mybatis的xml配置类

解析流程

1、propertiesElement方法
  • 获取<properties>标签的子标签<property>的属性放入properties实例中
  • 通过<properties>标签的resource或者url属性获取properties实例并覆盖
  • XMLConfigBuilder构造器中会传入一个Properties实例,然后不为null则继续覆盖
2、settingsAsProperteis方法
  • 获取<settings>子标签,然后生成Properties实例
  • 遍历第一步获取的Properties属性,通过MetaClass获取Configuration是否存在对应属性,如果不存在则抛出异常
  • 此处涉及到了反射工具类,MeataClass|Reflector|ReflectorFactory
  • 该方法只是解析了<settings>标签但是并没有把属性设置到Configuration实例中
3、loadCustomVfs方法

通过Resources#forName加载VFS类的子类,用来加载资源的

4、loadCustomLogImpl方法

通过别名的方式去加载日志Log实现类,若不存在别名则通过Resources#forName加载,Configuration在无参构造器中已经注册了许多,如SLF4J、COMMONS_LOGGING、LOG4J、LOG4J2、JDK_LOGGING、STDOUT_LOGGING、NO_LOGGING

5、typeAliasesElement方法

package注册

  • 获取<package>标签的name属性
  • Configuration#getTypeAliasRegistry#registerAliaes(package#name)
  • ResolverUtil#find方法获取所有对应包下的所有Object对象
  • 遍历所有类,过滤所有内部类、接口、成员类
  • 默认使用Class#getSimpleName,若类存在@Alias则使用注解的值
  • TypeAliasRegistry#registerAlias,别名最后会变成英文小写的

typeAlias注册

  • 通过<typeAlias>获取alias和type属性
  • 调用TypeAliasRegistry#registerAlias注册
6、pluginElement方法
  • 获取所有plugin子节点
  • 通过反射newInstance实例化
  • 调用Configuration#addInterceptor添加插件
7、objectFactoryElement方法

ObjectFactory是MyBatis用来创建所有需要的Object

  • 获取type属性,然后反射实例化
  • 调用Configuration#setObjectFactory
  • 默认就是DefaultObjectFactory,可以自己继承ObjectFactory接口实现
8、objectWrapperFactoryElement方法

同上,类似的。默认DefaultObjectWrapperFactory

9、reflectorFactoryElement方法
10、settingsElement方法

此处真正的将settings的配置设置了

11、environmentsElement方法
  • 获取属性default作为默认environment的值
  • 获取子标签的id、transactionManager、dataSource属性
  • 通过Environment#Builder#build构建Environment实例
12、databaseIdProviderElement方法

获取数据库方言id

13、typeHandlerElement方法

类似typeAliasesElement注册

14、mapperElement方法

解析mapper文件,很重要,下一章解释

0x04 解析总结

解析过程还是很清晰的,就是<settings>的解析和设置为什么分两步存在疑问!mapperElement的解析也是类似<configuration>的解析,都是通过BaseBuilder的子类去解析

0x05 涉及类

反射工具类:MetaClass、Reflector、ReflectorFactory

数据库:TransactionFactory、DataSourceFactory、DataSource

三、反射工具类

0x01 MetaClass

作用:解析一些名称,然后实际通过Reflector实例对类的元信息进行判断

原理:

  • 通过forClass方法生成MetaClass类实例
  • 内部存放Reflector实例和ReflectorFactory实例
  • ReflectorFactory实例是为了生成Reflector
  • ReflectorFactory来自XMLConfigBuilder

0x02 Reflector

作用:根据Class类解析其类的元信息并存储

原理:通过java的反射方式对类元信息进行分析,然后存储

解析过程:

1、addDefaultConstructor

  • 通过jdk8stream api获取任何一个无参构造器,给成员变量defaultConstructor

2、addGetMethods

  • Map<String, List<Method>>存放的是属性对应的方法,可能存在冲突

  • 调用getClassMethods获取所有方法

  • 调用PropertyNamer#isGetter过滤所有无参get方法

  • 调用PropertyNamer#methodToProperty将所有get或者is开头的方法转换成其属性名,如getTitle或者isTitle都变成title

  • 调用addMethodConflict将转换后的方法冲突方法加入List

  • 调用resolveGetterConflicts解决冲突并将方法加入getMethods成员属性

3、addSetMethods

类似addGetMethods,冲突解决方法不同,set方法优先选择参数是子类的方法,若类型不相关则抛出异常

4、addFields

  • 通过Class#getDeclaredFields获取所有成员属性
  • 获取成员属性名,若不存在get方法则加入,若不存在set方法且成员属性非static final则加入set方法
  • 这里添加的set和get方法是Invoker的不同子类

5、可读/可写属性信息存储

其他方法:

1、getClassMethods

  • Class#getDeclaredMethods通过addUniqueMethods放入map
  • Class#getInterfaces通过addUniqueMethods放入map
  • 通过while循环将其父类中的方法也放入,若父类是Object则跳过
  • 将所有方法的map转换成数组返回

2、addUniqueMethods

通过getSignature方法获取方法签名,若不存在则放入map中,跳过桥接方法Method#isBridge

3、getSignature

获取方法签名字符串,格式:返回值#方法名称:参数1,参数2…,如java.lang.Integer#getId:java.lang.String,java.lang.Integer

4、resolveGetterConflicts

  • 若返回值是boolean类型,则优先取is开头的方法;若返回值非boolean类型,且有is和get开头的方法则抛出异常
  • 若winnerType是candidateType的子类,则默认winnerType更好
  • 若candidateType是winnerType的子类,则candidateType更好
  • 调用addGetMethod方法将最适合的方法加入get方法map中

5、addGetMethod

  • 调用isValidPropertyName验证属性名,非$开头、非serialVersionUID、非class
  • getMethods.put(name, new MethodInvoker(method))
  • 调用TypeParameterResolver#resolveReturnType获取方法的returnType
  • getTypes.put(name, typeToClass(returnType))将返回值转换成Class存入map

0x03 ReflectorFactory

作用:生成Reflector、并且能够缓存Reflector

原理:

  • 核心方法findForClass,根据对应Class对象生成Reflector实例
  • 成员变量classCacheEnabled控制是否缓存对应Class的Reflector实例
  • 实例缓存在ConcurrentHashMap中

0x04 PropertyTokenizer

作用:属性分词器,处理比较复杂的属性名

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值