上次講到了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;
}
}
}