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;
      }
    }
  }

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