Mybatis源碼分析(二)

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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章