一、解析流程
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
作用:属性分词器,处理比较复杂的属性名