主要记录自己看Mybatis源码的过程,写的不是很好只能自己看懂,见谅。
如下typeAliases解析主要是靠XMLConfigBuilder这个类。
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<typeAliases>
<package name="com.danielei.entity"></package>
</typeAliases>
省略其他。。
</configuration>
org.apache.ibatis.builder.xml.XMLConfigBuilder#parse
此方法解析mybatis-config.xml中节点名称为configuration的标签
public Configuration parse() {
if (parsed) {
throw new BuilderException("Each XMLConfigBuilder can only be used once.");
}
parsed = true;
//跟踪一下此方法
parseConfiguration(parser.evalNode("/configuration"));
return configuration;
}
追踪parseConfiguration方法
org.apache.ibatis.builder.xml.XMLConfigBuilder#parseConfiguration
此方法 解析一大推标签,我此时只看 typeAliasesElement(root.evalNode(“typeAliases”));这行
private void parseConfiguration(XNode root) {
try {
//issue #117 read properties first
propertiesElement(root.evalNode("properties"));
Properties settings = settingsAsProperties(root.evalNode("settings"));
loadCustomVfs(settings);
//===分隔符=========
//只看这行只看这行只看这行只看这行
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 #631
environmentsElement(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);
}
}
追踪typeAliasesElement这个方法
这个方法主要干的就是循环typeAliases的子节点,如果节点的名称等于"package"
//找到这行配置
<package name="com.danielei.entity"></package>
org.apache.ibatis.builder.xml.XMLConfigBuilder#typeAliasesElement
private void typeAliasesElement(XNode parent) {
if (parent != null) {
for (XNode child : parent.getChildren()) {
//true 进入此分支
if ("package".equals(child.getName())) {
// 获取package节点的name属性
//typeAliasPackage =“com.danielei.entity”
String typeAliasPackage = child.getStringAttribute("name");
//把包名传过去 我们再跟一下这个方法。
configuration.getTypeAliasRegistry().registerAliases(typeAliasPackage);
} else {
String alias = child.getStringAttribute("alias");
String type = child.getStringAttribute("type");
try {
Class<?> clazz = Resources.classForName(type);
if (alias == null) {
typeAliasRegistry.registerAlias(clazz);
} else {
typeAliasRegistry.registerAlias(alias, clazz);
}
} catch (ClassNotFoundException e) {
throw new BuilderException("Error registering typeAlias for '" + alias + "'. Cause: " + e, e);
}
}
}
}
}
org.apache.ibatis.type.TypeAliasRegistry#registerAliases(java.lang.String)
//跟过来如下代码
public void registerAliases(String packageName){
//继续跟踪
registerAliases(packageName, Object.class);
}
org.apache.ibatis.type.TypeAliasRegistry#registerAliases(java.lang.String, java.lang.Class<?>)
继续跟踪 代码如下
public void registerAliases(String packageName, Class<?> superType){
ResolverUtil<Class<?>> resolverUtil = new ResolverUtil<Class<?>>();
//这行代码把包名传过去了 跟过去看看
resolverUtil.find(new ResolverUtil.IsA(superType), packageName);
Set<Class<? extends Class<?>>> typeSet = resolverUtil.getClasses();
for(Class<?> type : typeSet){
// Ignore inner classes and interfaces (including package-info.java)
// Skip also inner classes. See issue #6
if (!type.isAnonymousClass() && !type.isInterface() && !type.isMemberClass()) {
registerAlias(type);
}
}
}
org.apache.ibatis.io.ResolverUtil#find
代码如下
- public ResolverUtil<T> find(Test test, String packageName) { //
把包名中的.转换为/ 就是下面这行代码。 //return packageName == null ? null :
packageName.replace('.', '/');
String path = getPackagePath(packageName);
try {
//这行代码获取到 包下的文件路径,包名+XXX.class ,包名+User.class 等等文件
List<String> children = VFS.getInstance().list(path);
for (String child : children) {
if (child.endsWith(".class")) {
//跟踪一下这个方法
addIfMatching(test, child);
}
}
} catch (IOException ioe) {
log.error("Could not read package: " + packageName, ioe);
}
return this; }
org.apache.ibatis.io.ResolverUtil#addIfMatching
代码如下
protected void addIfMatching(Test test, String fqn) {
try {
//截取字串 = .class不要,并且把 /替换成. 得出 com.danielei.entity.UserEntity
String externalName = fqn.substring(0, fqn.indexOf('.')).replace('/', '.');
ClassLoader loader = getClassLoader();
if (log.isDebugEnabled()) {
log.debug("Checking to see if class " + externalName + " matches criteria [" + test + "]");
}
//这里直接把类实例
Class<?> type = loader.loadClass(externalName);
if (test.matches(type)) {
//放入Set集合中 方法跑完了,回到主线方法
matches.add((Class<T>) type);
}
} catch (Throwable t) {
log.warn("Could not examine class '" + fqn + "'" + " due to a " +
t.getClass().getName() + " with message: " + t.getMessage());
}
}
org.apache.ibatis.type.TypeAliasRegistry#registerAliases(java.lang.String, java.lang.Class<?>)
回到此方法
public void registerAliases(String packageName, Class<?> superType){
ResolverUtil<Class<?>> resolverUtil = new ResolverUtil<Class<?>>();
resolverUtil.find(new ResolverUtil.IsA(superType), packageName);
//此时执行这行代码 获取刚才存实体的Set集合数据。
Set<Class<? extends Class<?>>> typeSet = resolverUtil.getClasses();
for(Class<?> type : typeSet){
// Ignore inner classes and interfaces (including package-info.java)
// Skip also inner classes. See issue #6
if (!type.isAnonymousClass() && !type.isInterface() && !type.isMemberClass()) {
//进入此方法 跟踪一下
registerAlias(type);
}
}
}
org.apache.ibatis.type.TypeAliasRegistry#registerAlias(java.lang.Class<?>)
跟踪此方法
public void registerAlias(Class<?> type) {
//这里获取 类名=UserEntity
String alias = type.getSimpleName();
//获取类上的注解 @Alias("自定义名称")
Alias aliasAnnotation = type.getAnnotation(Alias.class);
//有设置注解取注解的自定义名称,没设置该注解默认是 类名
if (aliasAnnotation != null) {
alias = aliasAnnotation.value();
}
//跟踪此方法
registerAlias(alias, type);
}
如图自定义别名
org.apache.ibatis.type.TypeAliasRegistry#registerAlias(java.lang.String, java.lang.Class<?>)
public void registerAlias(String alias, Class<?> value) {
if (alias == null) {
throw new TypeException("The parameter alias cannot be null");
}
// issue #748
//把类名转为小写当作Map中的key。
String key = alias.toLowerCase(Locale.ENGLISH);
if (TYPE_ALIASES.containsKey(key) && TYPE_ALIASES.get(key) != null && !TYPE_ALIASES.get(key).equals(value)) {
throw new TypeException("The alias '" + alias + "' is already mapped to the value '" + TYPE_ALIASES.get(key).getName() + "'.");
}
//最重要的代码,扫描的实体会存放在这个Map中。 key为小写类名,value是实例
TYPE_ALIASES.put(key, value);
}
到这里typeAliases核心代码就是这样了。
总结:mybatis-config.xml配置typeAliases标签 解析主要是XML技术
先解析父节点 <configuration>
然后解析<typeAliases>标签
再解析<typeAliases>标签下的子标签<package name="com.danielei.entity"></package>
然后获取 name属性,获取到这个包路径后,去找到改路径下的文件,把.class类文件结尾的拿到存入List中,此时是多个包名+文件名组成的字符串,然后循环实例化并存入Set集合中。 再用Set集合循环 存入Map中 key为(小写的)类名,value就是类实例。