美文网首页
TypeAliasRegistry源码分析

TypeAliasRegistry源码分析

作者: BestbpF | 来源:发表于2018-09-10 22:31 被阅读6次

简述

typeAlias即类型别名,我们在使用mybatis时经常会设置并使用这一功能,如在编写XML映射SQL语句中的parameterType,resultType属性时,我们会直接使用String,而不是java.lang.String,帮助我们完成这一简化过程的就是TypeAliasRegistry类。

源码分析

与之前文章TypeHandlerRegistry源码简单分析类似,TypeAliasRegistry也是使用一个Map(这里是HashMap)去维护别名与真实类的对应关系

private final Map<String, Class<?>> TYPE_ALIASES = new HashMap<String, Class<?>>();

TypeAliasRegistry在初始化时,便在无参构造函数中帮我们完成了一些基础别名的映射实现,源码如下

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

    //mybatis中的resultSet
    registerAlias("ResultSet", ResultSet.class);
  }

TypeAliasRegistry提供了三种registerAlias的实现,源码如下
【最核心的方法】

  //逻辑清晰明了
  public void registerAlias(String alias, Class<?> value) {
    if (alias == null) {
      throw new TypeException("The parameter alias cannot be null");
    }
    // issue #748
    //别名统一转换为小写去比较
    String key = alias.toLowerCase(Locale.ENGLISH);
    if (TYPE_ALIASES.containsKey(key) && TYPE_ALIASES.get(key) != null && !TYPE_ALIASES.get(key).equals(value)) {
      //如果map中存在该k,v,则抛出对应异常
      throw new TypeException("The alias '" + alias + "' is already mapped to the value '" + TYPE_ALIASES.get(key).getName() + "'.");
    }
    //否则存入map(key存在覆盖,不存在新增)
    TYPE_ALIASES.put(key, value);
  }

其它的registerAlias主要是方便用户去自定义别名,最终都会指向核心方法


【包扫描】

  public void registerAliases(String packageName){
    registerAliases(packageName, Object.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);//指向【类型扫描】
      }
    }
  }

对应我们常用的包扫描注册方式

  <typeAliases>
      <package name="com.xx.xx.xx"/>
  </typeAliases>

【类型扫描】
参数只有一个Class<?> type,默认别名为该类的首字母小写,然后会判断该类是否被@Alias注解修饰并指定别名,如果有则使用该别名,没有的话就还是首字母小写,然后指向核心方法进行注册

  public void registerAlias(Class<?> type) {
    String alias = type.getSimpleName();
    Alias aliasAnnotation = type.getAnnotation(Alias.class);
    if (aliasAnnotation != null) {
      alias = aliasAnnotation.value();
    } 
    registerAlias(alias, type);
  }

对应【类型】注册方式

  <typeAliases>
      <typeAlias type="com.xxx.xx.User"/>
  </typeAliases>

【类型,类全名扫描】
通过反射将类全名解析为Class类,然后指向核心方法

  public void registerAlias(String alias, String value) {
    try {
      registerAlias(alias, Resources.classForName(value));
    } catch (ClassNotFoundException e) {
      throw new TypeException("Error registering type alias "+alias+" for "+value+". Cause: " + e, e);
    }
  }

对应【类型,类全名】注册方式

  <typeAliases>
      <typeAlias type="com.xxx.xx.User" alias="user" />
  </typeAliases>

【别名解析】
当我们使用别名时,通过TypeAliasRegistry的resolveAlias进行解析得到实际的类

  public <T> Class<T> resolveAlias(String string) {
    try {
      if (string == null) {
        return null;
      }
      // issue #748
      //mybatis默认的别名均为小写,但是写成大写也无妨,因为解析时通通转化为小写
      String key = string.toLowerCase(Locale.ENGLISH);
      Class<T> value;
      if (TYPE_ALIASES.containsKey(key)) {
        //map中存在对应key、value则取出value
        value = (Class<T>) TYPE_ALIASES.get(key);
      } else {
        //不存在则直接通过反射获取Class,即我们在使用时可以直接写全名
        value = (Class<T>) Resources.classForName(string);
      }
      return value;
    } catch (ClassNotFoundException e) {
      throw new TypeException("Could not resolve type alias '" + string + "'.  Cause: " + e, e);
    }
  }

除了TypeAliasRegistry自带的别名映射外,Configuration类在实例化时也提供了很多默认的别名映射实现

  public Configuration() {
    //事务方式
    typeAliasRegistry.registerAlias("JDBC", JdbcTransactionFactory.class);
    typeAliasRegistry.registerAlias("MANAGED", ManagedTransactionFactory.class);

    //数据源类型
    typeAliasRegistry.registerAlias("JNDI", JndiDataSourceFactory.class);
    typeAliasRegistry.registerAlias("POOLED", PooledDataSourceFactory.class);
    typeAliasRegistry.registerAlias("UNPOOLED", UnpooledDataSourceFactory.class);

    //缓存策略
    typeAliasRegistry.registerAlias("PERPETUAL", PerpetualCache.class);
    typeAliasRegistry.registerAlias("FIFO", FifoCache.class);
    typeAliasRegistry.registerAlias("LRU", LruCache.class);
    typeAliasRegistry.registerAlias("SOFT", SoftCache.class);
    typeAliasRegistry.registerAlias("WEAK", WeakCache.class);
    
    //数据库标识
    typeAliasRegistry.registerAlias("DB_VENDOR", VendorDatabaseIdProvider.class);

    //语言驱动类
    typeAliasRegistry.registerAlias("XML", XMLLanguageDriver.class);
    typeAliasRegistry.registerAlias("RAW", RawLanguageDriver.class);

    //日志类
    typeAliasRegistry.registerAlias("SLF4J", Slf4jImpl.class);
    typeAliasRegistry.registerAlias("COMMONS_LOGGING", JakartaCommonsLoggingImpl.class);
    typeAliasRegistry.registerAlias("LOG4J", Log4jImpl.class);
    typeAliasRegistry.registerAlias("LOG4J2", Log4j2Impl.class);
    typeAliasRegistry.registerAlias("JDK_LOGGING", Jdk14LoggingImpl.class);
    typeAliasRegistry.registerAlias("STDOUT_LOGGING", StdOutImpl.class);
    typeAliasRegistry.registerAlias("NO_LOGGING", NoLoggingImpl.class);

    //动态代理类
    typeAliasRegistry.registerAlias("CGLIB", CglibProxyFactory.class);
    typeAliasRegistry.registerAlias("JAVASSIST", JavassistProxyFactory.class);
  }

相关文章

网友评论

      本文标题:TypeAliasRegistry源码分析

      本文链接:https://www.haomeiwen.com/subject/hcmegftx.html