上次讲到了XMLConfigBuilder解析mybatis核心配置文件的过程当中的别名解析的过程
public class TypeAliasRegistry {
//是我们的所有的别名都是存储在这个Map当中,他使用的小写简当key,而value是我们的字节码类名,里面存储的是所有的另名
private final Map<String, Class<?>> TYPE_ALIASES = new HashMap<String, Class<?>>();
//默认注册的别名,有基本的数据类型和集合类型,还有迭代器类型
public TypeAliasRegistry() {
registerAlias("string", String.class);
registerAlias("byte", Byte.class);
registerAlias("long", Long.class);
registerAlias("short", Short.class);
registerAlias("int", Integer.class);
registerAlias("integer", Integer.class);
registerAlias("double", Double.class);
registerAlias("float", Float.class);
registerAlias("boolean", Boolean.class);
registerAlias("byte[]", Byte[].class);
registerAlias("long[]", Long[].class);
registerAlias("short[]", Short[].class);
registerAlias("int[]", Integer[].class);
registerAlias("integer[]", Integer[].class);
registerAlias("double[]", Double[].class);
registerAlias("float[]", Float[].class);
registerAlias("boolean[]", Boolean[].class);
registerAlias("_byte", byte.class);
registerAlias("_long", long.class);
registerAlias("_short", short.class);
registerAlias("_int", int.class);
registerAlias("_integer", int.class);
registerAlias("_double", double.class);
registerAlias("_float", float.class);
registerAlias("_boolean", boolean.class);
registerAlias("_byte[]", byte[].class);
registerAlias("_long[]", long[].class);
registerAlias("_short[]", short[].class);
registerAlias("_int[]", int[].class);
registerAlias("_integer[]", int[].class);
registerAlias("_double[]", double[].class);
registerAlias("_float[]", float[].class);
registerAlias("_boolean[]", boolean[].class);
registerAlias("date", Date.class);
registerAlias("decimal", BigDecimal.class);
registerAlias("bigdecimal", BigDecimal.class);
registerAlias("biginteger", BigInteger.class);
registerAlias("object", Object.class);
registerAlias("date[]", Date[].class);
registerAlias("decimal[]", BigDecimal[].class);
registerAlias("bigdecimal[]", BigDecimal[].class);
registerAlias("biginteger[]", BigInteger[].class);
registerAlias("object[]", Object[].class);
registerAlias("map", Map.class);
registerAlias("hashmap", HashMap.class);
registerAlias("list", List.class);
registerAlias("arraylist", ArrayList.class);
registerAlias("collection", Collection.class);
registerAlias("iterator", Iterator.class);
registerAlias("ResultSet", ResultSet.class);
}
}
别名的注册过程如下
public void registerAlias(String alias, Class<?> value) {
if (alias == null) throw new TypeException("The parameter alias cannot be null");
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() + "'.");
}
TYPE_ALIASES.put(key, value);//放入到 Map集合当中
}
别名的解析过程如下
//根据别名的key来获取相应的类命名的过程,也就是获取map当中的value过程
// throws class cast exception as well if types cannot be assigned
public <T> Class<T> resolveAlias(String string) {
try {
if (string == null) return null;
String key = string.toLowerCase(Locale.ENGLISH); // 转成小写,所以我们的写别名的和类型时没有大小写之分
Class<T> value;
if (TYPE_ALIASES.containsKey(key)) { //如果这个类型别名有在Map当中注册,则获取
value = (Class<T>) TYPE_ALIASES.get(key);
} else {
value = (Class<T>) Resources.classForName(string); //没有则进行加载这个类
}
return value;
} catch (ClassNotFoundException e) {
throw new TypeException("Could not resolve type alias '" + string + "'. Cause: " + e, e);
}
}
解析mybatis的核心的配置的其他的选项就不解析,差不多都是这个原理,下面进行解析我们的XMLMapperBuilder解析Mapper.xml文件封装到Configration的过程
先来看一下我们的Configration关于封装我们的Mapper.xml相关的数据的内容字段如下
//这个mappedStatements 主要是用来封装我们的下面的那部分delete|select|update|insert的那部分sql内容的
protected final Map<String, MappedStatement> mappedStatements = new StrictMap<MappedStatement>("Mapped Statements collection");
protected final Map<String, Cache> caches = new StrictMap<Cache>("Caches collection");
//这个主要是用来封装我resultMap相关的内容的
protected final Map<String, ResultMap> resultMaps = new StrictMap<ResultMap>("Result Maps collection");
// 这个主要是用来封装我们的传入的参数的
protected final Map<String, ParameterMap> parameterMaps = new StrictMap<ParameterMap>("Parameter Maps collection"); protected final Map<String, KeyGenerator> keyGenerators = new StrictMap<KeyGenerator>("Key Generators collection");
StrictMap的数据结构的说明
/**
* 这个数据结构是我们的Mybatis的Configration当中的使用的封装配置的结构体
* @author Administrator
*
* @param <V>
*/
public class MyStrictMap<V> extends HashMap<String, V> {
private static final long serialVersionUID = -4950446264854982944L;
private final String name;
public MyStrictMap(String name, int initialCapacity, float loadFactor) {
super(initialCapacity, loadFactor);
this.name = name;
}
public MyStrictMap(String name, int initialCapacity) {
super(initialCapacity);
this.name = name;
}
public MyStrictMap(String name) {
super();
this.name = name;
}
public MyStrictMap(String name, Map<String, ? extends V> m) {
super(m);
this.name = name;
}
/**
* 重写Map当中的put方法,有.的数据不会直接抛出已经存在key exception问题,只有标识多个key的问题
* 是在get那部分时才会出现问题
*/
@SuppressWarnings("unchecked")
public V put(String key, V value) {
//他是首先先来看一下这个配置的key是不是已经注册过了,如果是就的抛出exception,也就是保证key的唯一
if (containsKey(key)) {
throw new IllegalArgumentException(name + " already contains value for " + key);
}
//看一下这个key是不是包括.,如果是包含这个.点
if (key.contains(".")) {
//getShortName()方法获取了最后一个"."之后的字符,如:key=com.hailong.Hello,那么shortName=Hello
final String shortKey = getShortName(key);
if (super.get(shortKey) == null) {
//如果不存在,直接设置
super.put(shortKey, value);
} else {
//如果已经存在,设置为一个特殊的对象,标识shortName同时对应的了多个值
super.put(shortKey, (V) new Ambiguity(shortKey)); //最后取的是这个对象,如果是这个对象,则说明有同一个key,对应多个值了
}
}
//如果没有包含.则直接放入map当中
return super.put(key, value);
}
//根据key来获取数据
public V get(Object key) {
V value = super.get(key);
if (value == null) {
throw new IllegalArgumentException(name + " does not contain value for " + key);
}
//如果为特殊对象Ambiguity,同一个shortName有多个命名空间使用,所有不允许用shortName方法,必须加上命名空间访问
if (value instanceof Ambiguity) {
//
throw new IllegalArgumentException(((Ambiguity) value).getSubject() + " is ambiguous in " + name
+ " (try using the full name including the namespace, or rename one of the entries)");
}
return value;
}
//如果包含点,说明是全字点节码类名,那么则取出.分割的前面那部分数据
private String getShortName(String key) {
final String[] keyParts = key.split("\\.");
return keyParts[keyParts.length - 1];
}
//多个值,key相同,这里只是做一个标识,说明他是一个重名的参数
protected static class Ambiguity {
final private String subject;
public Ambiguity(String subject) {
this.subject = subject;
}
public String getSubject() {
return subject;
}
}
}